Merge "Avoid unnecessary SharedPrefences disk writes." into gingerbread
diff --git a/Android.mk b/Android.mk
index b1f43f8..9f92637 100644
--- a/Android.mk
+++ b/Android.mk
@@ -375,6 +375,8 @@
 # (see development/build/sdk.atree)
 web_docs_sample_code_flags := \
 		-hdf android.hasSamples 1 \
+		-samplecode $(sample_dir)/AccessibilityService \
+		            resources/samples/AccessibilityService "Accessibility Service" \
 		-samplecode $(sample_dir)/ApiDemos \
 		            resources/samples/ApiDemos "API Demos" \
 		-samplecode $(sample_dir)/BackupRestore \
diff --git a/api/9.xml b/api/9.xml
index f18623f..46f087f 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -379555,7 +379555,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value=""100-Continue""
+ value=""100-continue""
  static="true"
  final="true"
  deprecated="not deprecated"
diff --git a/api/current.xml b/api/current.xml
index f494775..61f5e16 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -403611,7 +403611,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value=""100-Continue""
+ value=""100-continue""
  static="true"
  final="true"
  deprecated="not deprecated"
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index f72de67..a0abc6c 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1138,9 +1138,9 @@
          */
         public static final String SCENE_MODE_BARCODE = "barcode";
 
-        // Values for focus mode settings.
         /**
-         * Auto-focus mode.
+         * Auto-focus mode. Applications should call {@link
+         * #autoFocus(AutoFocusCallback)} to start the focus in this mode.
          */
         public static final String FOCUS_MODE_AUTO = "auto";
 
@@ -1149,6 +1149,12 @@
          * {@link #autoFocus(AutoFocusCallback)} in this mode.
          */
         public static final String FOCUS_MODE_INFINITY = "infinity";
+
+        /**
+         * Macro (close-up) focus mode. Applications should call
+         * {@link #autoFocus(AutoFocusCallback)} to start the focus in this
+         * mode.
+         */
         public static final String FOCUS_MODE_MACRO = "macro";
 
         /**
@@ -1170,7 +1176,9 @@
          * Continuous auto focus mode. The camera continuously tries to focus.
          * This is ideal for shooting video or shooting photo of moving object.
          * Auto focus starts when the parameter is set. Applications should not
-         * call {@link #autoFocus(AutoFocusCallback)} in this mode.
+         * call {@link #autoFocus(AutoFocusCallback)} in this mode. To stop
+         * continuous focus, applications should change the focus mode to other
+         * modes.
          */
         public static final String FOCUS_MODE_CONTINUOUS = "continuous";
 
@@ -1948,6 +1956,7 @@
          * @see #FOCUS_MODE_INFINITY
          * @see #FOCUS_MODE_MACRO
          * @see #FOCUS_MODE_FIXED
+         * @see #FOCUS_MODE_EDOF
          * @see #FOCUS_MODE_CONTINUOUS
          */
         public String getFocusMode() {
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index f6d237a..d2c3eaa 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1525,7 +1525,22 @@
      * Typically the atmospheric pressure is read from a
      * {@link Sensor#TYPE_PRESSURE} sensor. The pressure at sea level must be
      * known, usually it can be retrieved from airport databases in the
-     * vicinity.
+     * vicinity. If unknown, you can use {@link #PRESSURE_STANDARD_ATMOSPHERE}
+     * as an approximation, but absolute altitudes won't be accurate.
+     * </p>
+     * <p>
+     * To calculate altitude differences, you must calculate the difference
+     * between the altitudes at both points. If you don't know the altitude
+     * as sea level, you can use {@link #PRESSURE_STANDARD_ATMOSPHERE} instead,
+     * which will give good results considering the range of pressure typically
+     * involved.
+     * </p>
+     * <p>
+     * <code><ul>
+     *  float altitude_difference =
+     *      getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, pressure_at_point2)
+     *      - getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, pressure_at_point1);
+     * </ul></code>
      * </p>
      *
      * @param p0 pressure at sea level
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
index 447e642..cafe0f9 100644
--- a/core/java/android/net/DownloadManager.java
+++ b/core/java/android/net/DownloadManager.java
@@ -51,14 +51,14 @@
     public final static String COLUMN_ID = "id";
 
     /**
-     * The client-supplied title for this download.  This will be displayed in system notifications,
-     * if enabled.
+     * The client-supplied title for this download.  This will be displayed in system notifications.
+     * Defaults to the empty string.
      */
     public final static String COLUMN_TITLE = "title";
 
     /**
      * The client-supplied description of this download.  This will be displayed in system
-     * notifications, if enabled.
+     * notifications.  Defaults to the empty string.
      */
     public final static String COLUMN_DESCRIPTION = "description";
 
@@ -68,22 +68,24 @@
     public final static String COLUMN_URI = "uri";
 
     /**
-     * Internet Media Type of the downloaded file.  This will be filled in based on the server's
-     * response once the download has started.
+     * Internet Media Type of the downloaded file.  If no value is provided upon creation, this will
+     * initially be null and will be filled in based on the server's response once the download has
+     * started.
      *
      * @see <a href="http://www.ietf.org/rfc/rfc1590.txt">RFC 1590, defining Media Types</a>
      */
     public final static String COLUMN_MEDIA_TYPE = "media_type";
 
     /**
-     * Total size of the download in bytes.  This will be filled in once the download starts.
+     * Total size of the download in bytes.  This will initially be -1 and will be filled in once
+     * the download starts.
      */
     public final static String COLUMN_TOTAL_SIZE_BYTES = "total_size";
 
     /**
      * Uri where downloaded file will be stored.  If a destination is supplied by client, that URI
-     * will be used here.  Otherwise, the value will be filled in with a generated URI once the
-     * download has started.
+     * will be used here.  Otherwise, the value will initially be null and will be filled in with a
+     * generated URI once the download has started.
      */
     public final static String COLUMN_LOCAL_URI = "local_uri";
 
@@ -688,8 +690,13 @@
             if (column.equals(COLUMN_MEDIA_TYPE)) {
                 return getUnderlyingString(Downloads.COLUMN_MIME_TYPE);
             }
+
             assert column.equals(COLUMN_LOCAL_URI);
-            return Uri.fromFile(new File(getUnderlyingString(Downloads._DATA))).toString();
+            String localUri = getUnderlyingString(Downloads._DATA);
+            if (localUri == null) {
+                return null;
+            }
+            return Uri.fromFile(new File(localUri)).toString();
         }
 
         private long translateLong(String column) {
diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java
index 1da6d7a..d634672 100644
--- a/core/java/android/pim/vcard/VCardBuilder.java
+++ b/core/java/android/pim/vcard/VCardBuilder.java
@@ -1463,6 +1463,9 @@
                     parameterList.add(VCardConstants.PARAM_TYPE_VOICE);
                 } else if (VCardUtils.isMobilePhoneLabel(label)) {
                     parameterList.add(VCardConstants.PARAM_TYPE_CELL);
+                } else if (mIsV30) {
+                    // This label is appropriately encoded in appendTypeParameters.
+                    parameterList.add(label);
                 } else {
                     final String upperLabel = label.toUpperCase();
                     if (VCardUtils.isValidInV21ButUnknownToContactsPhoteType(upperLabel)) {
@@ -1741,21 +1744,30 @@
         // which would be recommended way in vcard 3.0 though not valid in vCard 2.1.
         boolean first = true;
         for (final String typeValue : types) {
-            // Note: vCard 3.0 specifies the different type of acceptable type Strings, but
-            //       we don't emit that kind of vCard 3.0 specific type since there should be
-            //       high probabilyty in which external importers cannot understand them.
-            //
-            // e.g. TYPE="\u578B\u306B\u3087" (vCard 3.0 allows non-Ascii characters if they
-            //      are quoted.)
-            if (!VCardUtils.isV21Word(typeValue)) {
-                continue;
+            if (VCardConfig.isV30(mVCardType)) {
+                // Note: vCard 3.0 specifies the different type of acceptable type Strings, but
+                //       we don't emit that kind of vCard 3.0 specific type since there should be
+                //       high probabilyty in which external importers cannot understand them.
+                //
+                // e.g. TYPE="\u578B\u306B\u3087" (vCard 3.0 allows non-Ascii characters if they
+                //      are quoted.)
+                if (first) {
+                    first = false;
+                } else {
+                    mBuilder.append(VCARD_PARAM_SEPARATOR);
+                }
+                appendTypeParameter(VCardUtils.toStringAvailableAsV30ParameValue(typeValue));
+            } else {  // vCard 2.1
+                if (!VCardUtils.isV21Word(typeValue)) {
+                    continue;
+                }
+                if (first) {
+                    first = false;
+                } else {
+                    mBuilder.append(VCARD_PARAM_SEPARATOR);
+                }
+                appendTypeParameter(typeValue);
             }
-            if (first) {
-                first = false;
-            } else {
-                mBuilder.append(VCARD_PARAM_SEPARATOR);
-            }
-            appendTypeParameter(typeValue);
         }
     }
 
diff --git a/core/java/android/pim/vcard/VCardEntryConstructor.java b/core/java/android/pim/vcard/VCardEntryConstructor.java
index 290ca2b..ae4ec29 100644
--- a/core/java/android/pim/vcard/VCardEntryConstructor.java
+++ b/core/java/android/pim/vcard/VCardEntryConstructor.java
@@ -157,11 +157,15 @@
         mParamType = type;
     }
 
+    @Override
     public void propertyParamValue(String value) {
         if (mParamType == null) {
             // From vCard 2.1 specification. vCard 3.0 formally does not allow this case.
             mParamType = "TYPE";
         }
+        if (!VCardUtils.containsOnlyAlphaDigitHyphen(value)) {
+            value = encodeString(value, mCharsetForDecodedBytes);
+        }
         mCurrentProperty.addParameter(mParamType, value);
         mParamType = null;
     }
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
index 11b112b..f972799 100644
--- a/core/java/android/pim/vcard/VCardUtils.java
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -16,10 +16,10 @@
 package android.pim.vcard;
 
 import android.content.ContentProviderOperation;
-import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Data;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 
@@ -477,6 +477,43 @@
         return true;
     }
 
+    /**
+     * <P>
+     * Returns String available as parameter value in vCard 3.0.
+     * </P>
+     * <P>
+     * RFC 2426 requires vCard composer to quote parameter values when it contains
+     * semi-colon, for example (See RFC 2426 for more information).
+     * This method checks whether the given String can be used without quotes.
+     * </P>
+     * <P>
+     * Note: We remove DQUOTE silently for now.
+     * </P>
+     */
+    public static String toStringAvailableAsV30ParameValue(String value) {
+        if (TextUtils.isEmpty(value)) {
+            value = "";
+        }
+        final int asciiFirst = 0x20;
+        final int asciiLast = 0x7E;  // included
+        final StringBuilder builder = new StringBuilder();
+        final int length = value.length();
+        boolean needQuote = false;
+        for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
+            final int codePoint = value.codePointAt(i);
+            if (codePoint < asciiFirst || codePoint == '"') {
+                // CTL characters and DQUOTE are never accepted. Remove them.
+                continue;
+            }
+            builder.appendCodePoint(codePoint);
+            if (codePoint == ':' || codePoint == ',' || codePoint == ' ') {
+                needQuote = true;
+            }
+        }
+        final String result = builder.toString();
+        return ((needQuote || result.isEmpty()) ? ('"' + result + '"') : result);
+    }
+
     public static String toHalfWidthString(final String orgString) {
         if (TextUtils.isEmpty(orgString)) {
             return null;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 2ca08ea..402443c 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -990,7 +990,8 @@
                             }
                         }) : 0;
         long durationDraw =
-                (root || (view.mPrivateFlags & View.DRAWN) != 0) ? profileViewOperation(view,
+                (root || !view.willNotDraw() || (view.mPrivateFlags & View.DRAWN) != 0) ? profileViewOperation(
+                        view,
                         new ViewOperation<Object>() {
                             public Object[] pre() {
                                 final DisplayMetrics metrics =
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 7392442..903283e 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -493,6 +493,15 @@
     return doBooleanCommand("BLACKLIST clear", "OK");
 }
 
+static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject clazz, jboolean enabled)
+{
+    char cmdstr[25];
+
+    snprintf(cmdstr, sizeof(cmdstr), "DRIVER SETSUSPEND %d", enabled ? 0 : 1);
+    return doBooleanCommand(cmdstr, "OK");
+}
+
+
 static jboolean android_net_wifi_doDhcpRequest(JNIEnv* env, jobject clazz, jobject info)
 {
     jint ipaddr, gateway, mask, dns1, dns2, server, lease;
@@ -571,6 +580,7 @@
     { "setScanResultHandlingCommand", "(I)Z", (void*) android_net_wifi_setScanResultHandlingCommand },
     { "addToBlacklistCommand", "(Ljava/lang/String;)Z", (void*) android_net_wifi_addToBlacklistCommand },
     { "clearBlacklistCommand", "()Z", (void*) android_net_wifi_clearBlacklistCommand },
+    { "setSuspendOptimizationsCommand", "(Z)Z", (void*) android_net_wifi_setSuspendOptimizationsCommand},
 
     { "doDhcpRequest", "(Landroid/net/DhcpInfo;)Z", (void*) android_net_wifi_doDhcpRequest },
     { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_wifi_getDhcpError },
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 556d367..42f35d1 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -76,10 +76,14 @@
             STATUS_ZOMBIE
         };
 
-        Connection(const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop);
+        Connection(uint16_t id,
+                const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop);
 
         inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
 
+        // A unique id for this connection.
+        uint16_t id;
+
         Status status;
 
         sp<InputChannel> inputChannel;
@@ -91,29 +95,34 @@
         // The sequence number of the current event being dispatched.
         // This is used as part of the finished token as a way to determine whether the finished
         // token is still valid before sending a finished signal back to the publisher.
-        uint32_t messageSeqNum;
+        uint16_t messageSeqNum;
 
         // True if a message has been received from the publisher but not yet finished.
         bool messageInProgress;
     };
 
     Mutex mLock;
+    uint16_t mNextConnectionId;
     KeyedVector<int32_t, sp<Connection> > mConnectionsByReceiveFd;
 
+    ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
+
     static void handleInputChannelDisposed(JNIEnv* env,
             jobject inputChannelObj, const sp<InputChannel>& inputChannel, void* data);
 
     static bool handleReceiveCallback(int receiveFd, int events, void* data);
 
-    static jlong generateFinishedToken(int32_t receiveFd, int32_t messageSeqNum);
+    static jlong generateFinishedToken(int32_t receiveFd,
+            uint16_t connectionId, uint16_t messageSeqNum);
 
     static void parseFinishedToken(jlong finishedToken,
-            int32_t* outReceiveFd, uint32_t* outMessageIndex);
+            int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex);
 };
 
 // ----------------------------------------------------------------------------
 
-NativeInputQueue::NativeInputQueue() {
+NativeInputQueue::NativeInputQueue() :
+        mNextConnectionId(0) {
 }
 
 NativeInputQueue::~NativeInputQueue() {
@@ -134,18 +143,17 @@
 
     sp<PollLoop> pollLoop = android_os_MessageQueue_getPollLoop(env, messageQueueObj);
 
-    int receiveFd;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        if (mConnectionsByReceiveFd.indexOfKey(receiveFd) >= 0) {
+        if (getConnectionIndex(inputChannel) >= 0) {
             LOGW("Attempted to register already registered input channel '%s'",
                     inputChannel->getName().string());
             return BAD_VALUE;
         }
 
-        sp<Connection> connection = new Connection(inputChannel, pollLoop);
+        uint16_t connectionId = mNextConnectionId++;
+        sp<Connection> connection = new Connection(connectionId, inputChannel, pollLoop);
         status_t result = connection->inputConsumer.initialize();
         if (result) {
             LOGW("Failed to initialize input consumer for input channel '%s', status=%d",
@@ -155,13 +163,14 @@
 
         connection->inputHandlerObjGlobal = env->NewGlobalRef(inputHandlerObj);
 
+        int32_t receiveFd = inputChannel->getReceivePipeFd();
         mConnectionsByReceiveFd.add(receiveFd, connection);
+
+        pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
     } // release lock
 
     android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
             handleInputChannelDisposed, this);
-
-    pollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
     return OK;
 }
 
@@ -177,38 +186,56 @@
     LOGD("channel '%s' - Unregistered", inputChannel->getName().string());
 #endif
 
-    int32_t receiveFd;
-    sp<Connection> connection;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
+        ssize_t connectionIndex = getConnectionIndex(inputChannel);
         if (connectionIndex < 0) {
             LOGW("Attempted to unregister already unregistered input channel '%s'",
                     inputChannel->getName().string());
             return BAD_VALUE;
         }
 
-        connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
         mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
 
         connection->status = Connection::STATUS_ZOMBIE;
 
+        connection->pollLoop->removeCallback(inputChannel->getReceivePipeFd());
+
         env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
         connection->inputHandlerObjGlobal = NULL;
+
+        if (connection->messageInProgress) {
+            LOGI("Sending finished signal for input channel '%s' since it is being unregistered "
+                    "while an input message is still in progress.",
+                    connection->getInputChannelName());
+            connection->messageInProgress = false;
+            connection->inputConsumer.sendFinishedSignal(); // ignoring result
+        }
     } // release lock
 
     android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);
-
-    connection->pollLoop->removeCallback(receiveFd);
     return OK;
 }
 
+ssize_t NativeInputQueue::getConnectionIndex(const sp<InputChannel>& inputChannel) {
+    ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
+    if (connectionIndex >= 0) {
+        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        if (connection->inputChannel.get() == inputChannel.get()) {
+            return connectionIndex;
+        }
+    }
+
+    return -1;
+}
+
 status_t NativeInputQueue::finished(JNIEnv* env, jlong finishedToken, bool ignoreSpuriousFinish) {
     int32_t receiveFd;
-    uint32_t messageSeqNum;
-    parseFinishedToken(finishedToken, &receiveFd, &messageSeqNum);
+    uint16_t connectionId;
+    uint16_t messageSeqNum;
+    parseFinishedToken(finishedToken, &receiveFd, &connectionId, &messageSeqNum);
 
     { // acquire lock
         AutoMutex _l(mLock);
@@ -216,16 +243,25 @@
         ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
         if (connectionIndex < 0) {
             if (! ignoreSpuriousFinish) {
-                LOGW("Attempted to finish input on channel that is no longer registered.");
+                LOGI("Ignoring finish signal on channel that is no longer registered.");
             }
             return DEAD_OBJECT;
         }
 
         sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        if (connectionId != connection->id) {
+            if (! ignoreSpuriousFinish) {
+                LOGI("Ignoring finish signal on channel that is no longer registered.");
+            }
+            return DEAD_OBJECT;
+        }
+
         if (messageSeqNum != connection->messageSeqNum || ! connection->messageInProgress) {
             if (! ignoreSpuriousFinish) {
-                LOGW("Attempted to finish input twice on channel '%s'.",
-                        connection->getInputChannelName());
+                LOGW("Attempted to finish input twice on channel '%s'.  "
+                        "finished messageSeqNum=%d, current messageSeqNum=%d, messageInProgress=%d",
+                        connection->getInputChannelName(),
+                        messageSeqNum, connection->messageSeqNum, connection->messageInProgress);
             }
             return INVALID_OPERATION;
         }
@@ -312,7 +348,7 @@
         connection->messageInProgress = true;
         connection->messageSeqNum += 1;
 
-        finishedToken = generateFinishedToken(receiveFd, connection->messageSeqNum);
+        finishedToken = generateFinishedToken(receiveFd, connection->id, connection->messageSeqNum);
 
         inputHandlerObjLocal = env->NewLocalRef(connection->inputHandlerObjGlobal);
     } // release lock
@@ -384,20 +420,23 @@
     return true;
 }
 
-jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, int32_t messageSeqNum) {
-    return (jlong(receiveFd) << 32) | jlong(messageSeqNum);
+jlong NativeInputQueue::generateFinishedToken(int32_t receiveFd, uint16_t connectionId,
+        uint16_t messageSeqNum) {
+    return (jlong(receiveFd) << 32) | (jlong(connectionId) << 16) | jlong(messageSeqNum);
 }
 
 void NativeInputQueue::parseFinishedToken(jlong finishedToken,
-        int32_t* outReceiveFd, uint32_t* outMessageIndex) {
+        int32_t* outReceiveFd, uint16_t* outConnectionId, uint16_t* outMessageIndex) {
     *outReceiveFd = int32_t(finishedToken >> 32);
-    *outMessageIndex = uint32_t(finishedToken & 0xffffffff);
+    *outConnectionId = uint16_t(finishedToken >> 16);
+    *outMessageIndex = uint16_t(finishedToken);
 }
 
 // ----------------------------------------------------------------------------
 
-NativeInputQueue::Connection::Connection(const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop) :
-    status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel),
+NativeInputQueue::Connection::Connection(uint16_t id,
+        const sp<InputChannel>& inputChannel, const sp<PollLoop>& pollLoop) :
+    id(id), status(STATUS_NORMAL), inputChannel(inputChannel), inputConsumer(inputChannel),
     pollLoop(pollLoop), inputHandlerObjGlobal(NULL),
     messageSeqNum(0), messageInProgress(false) {
 }
diff --git a/core/tests/coretests/res/raw/v30_multibyte_param.vcf b/core/tests/coretests/res/raw/v30_multibyte_param.vcf
new file mode 100644
index 0000000..cd200e5
--- /dev/null
+++ b/core/tests/coretests/res/raw/v30_multibyte_param.vcf
@@ -0,0 +1,5 @@
+BEGIN:VCARD

+VERSION:3.0

+N:F;G;M;;

+TEL;TYPE="่ดน":1

+END:VCARD

diff --git a/core/tests/coretests/src/android/pim/vcard/VCardImporterTests.java b/core/tests/coretests/src/android/pim/vcard/VCardImporterTests.java
index 21f2254..e0e1f87 100644
--- a/core/tests/coretests/src/android/pim/vcard/VCardImporterTests.java
+++ b/core/tests/coretests/src/android/pim/vcard/VCardImporterTests.java
@@ -1008,4 +1008,26 @@
                 .put(Phone.TYPE, Phone.TYPE_PAGER)
                 .put(Phone.NUMBER, "6101231234@pagersample.com");
     }
+
+    public void testMultiBytePropV30_Parse() {
+        mVerifier.initForImportTest(V30, R.raw.v30_multibyte_param);
+        mVerifier.addPropertyNodesVerifierElem()
+                .addExpectedNodeWithOrder("VERSION", "3.0")
+                .addExpectedNodeWithOrder("N", Arrays.asList("F", "G", "M", "", ""))
+                .addExpectedNodeWithOrder("TEL", "1", new TypeSet("\u8D39"));
+    }
+
+    public void testMultiBytePropV30() {
+        mVerifier.initForImportTest(V30, R.raw.v30_multibyte_param);
+        final ContentValuesVerifierElem elem = mVerifier.addContentValuesVerifierElem();
+        elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+                .put(StructuredName.FAMILY_NAME, "F")
+                .put(StructuredName.MIDDLE_NAME, "M")
+                .put(StructuredName.GIVEN_NAME, "G")
+                .put(StructuredName.DISPLAY_NAME, "G M F");
+        elem.addExpected(Phone.CONTENT_ITEM_TYPE)
+                .put(Phone.TYPE, Phone.TYPE_CUSTOM)
+                .put(Phone.LABEL, "\u8D39")
+                .put(Phone.NUMBER, "1");
+    }
 }
diff --git a/core/tests/coretests/src/android/pim/vcard/VCardUtilsTests.java b/core/tests/coretests/src/android/pim/vcard/VCardUtilsTests.java
index 59299f9..e805bee 100644
--- a/core/tests/coretests/src/android/pim/vcard/VCardUtilsTests.java
+++ b/core/tests/coretests/src/android/pim/vcard/VCardUtilsTests.java
@@ -82,4 +82,34 @@
             assertFalse(VCardUtils.containsOnlyAlphaDigitHyphen(String.valueOf((char)i)));
         }
     }
+
+    public void testToStringAvailableAsV30ParamValue() {
+        // Smoke tests.
+        assertEquals("HOME", VCardUtils.toStringAvailableAsV30ParameValue("HOME"));
+        assertEquals("TEL", VCardUtils.toStringAvailableAsV30ParameValue("TEL"));
+        assertEquals("PAGER", VCardUtils.toStringAvailableAsV30ParameValue("PAGER"));
+
+        assertEquals("\"\"", VCardUtils.toStringAvailableAsV30ParameValue(""));
+
+        // non-Ascii must be allowed
+        assertEquals("\u4E8B\u52D9\u6240",
+                VCardUtils.toStringAvailableAsV30ParameValue("\u4E8B\u52D9\u6240"));
+        // Reported as bug report.
+        assertEquals("\u8D39", VCardUtils.toStringAvailableAsV30ParameValue("\u8D39"));
+        assertEquals("\"comma,separated\"",
+                VCardUtils.toStringAvailableAsV30ParameValue("comma,separated"));
+        assertEquals("\"colon:aware\"",
+                VCardUtils.toStringAvailableAsV30ParameValue("colon:aware"));
+        // CTL characters.
+        assertEquals("CTLExample",
+                VCardUtils.toStringAvailableAsV30ParameValue("CTL\u0001Example"));
+        // DQUOTE must be removed.
+        assertEquals("quoted",
+                VCardUtils.toStringAvailableAsV30ParameValue("\"quoted\""));
+        // DQUOTE must be removed basically, but we should detect a space, which
+        // require us to use DQUOTE again.
+        // Right-side has one more illegal dquote to test quote-handle code thoroughly.
+        assertEquals("\"Already quoted\"",
+                VCardUtils.toStringAvailableAsV30ParameValue("\"Already quoted\"\""));
+    }
 }
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 6a5d254..99a3115 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -337,11 +337,14 @@
     static const char PIXEL_FORMAT_JPEG[];
 
     // Values for focus mode settings.
-    // Auto-focus mode.
+    // Auto-focus mode. Applications should call
+    // CameraHardwareInterface.autoFocus to start the focus in this mode.
     static const char FOCUS_MODE_AUTO[];
     // Focus is set at infinity. Applications should not call
     // CameraHardwareInterface.autoFocus in this mode.
     static const char FOCUS_MODE_INFINITY[];
+    // Macro (close-up) focus mode. Applications should call
+    // CameraHardwareInterface.autoFocus to start the focus in this mode.
     static const char FOCUS_MODE_MACRO[];
     // Focus is fixed. The camera is always in this mode if the focus is not
     // adjustable. If the camera has auto-focus, this mode can fix the
@@ -355,7 +358,8 @@
     // Continuous auto focus mode. The camera continuously tries to focus. This
     // is ideal for shooting video or shooting photo of moving object. Auto
     // focus starts when the parameter is set. Applications should not call
-    // CameraHardwareInterface.autoFocus in this mode.
+    // CameraHardwareInterface.autoFocus in this mode.  To stop continuous
+    // focus, applications should change the focus mode to other modes.
     static const char FOCUS_MODE_CONTINUOUS[];
 
     // The camera determines the exposure by giving more weight to the
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index dab35b3..3d42856 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -224,6 +224,7 @@
         uint8_t*        keyBitmask;
         KeyLayoutMap*   layoutMap;
         String8         keylayoutFilename;
+        int             fd;
         device_t*       next;
         
         device_t(int32_t _id, const char* _path, const char* name);
@@ -266,6 +267,12 @@
 #ifdef EV_SW
     int32_t         mSwitches[SW_MAX + 1];
 #endif
+
+    static const int INPUT_BUFFER_SIZE = 64;
+    struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
+    int32_t mInputBufferIndex;
+    int32_t mInputBufferCount;
+    int32_t mInputDeviceIndex;
 };
 
 }; // namespace android
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index d3495fe..2505cb0 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -554,6 +554,8 @@
     // All registered connections mapped by receive pipe file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
 
+    ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
+
     // Active connections are connections that have a non-empty outbound queue.
     // We don't use a ref-counted pointer here because we explicitly abort connections
     // during unregistration which causes the connection's outbound queue to be cleared
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 71c6c51..56d2765 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -480,10 +480,6 @@
         inline void clear() {
             fields = 0;
         }
-
-        inline bool isDirty() {
-            return fields != 0;
-        }
     } mAccumulator;
 
     float mXScale;
@@ -702,7 +698,7 @@
         } historyData[AVERAGING_HISTORY_SIZE];
     } mAveragingTouchFilter;
 
-    struct JumpTouchFilterState {
+    struct JumpyTouchFilterState {
         uint32_t jumpyPointsDropped;
     } mJumpyTouchFilter;
 
@@ -765,10 +761,6 @@
         inline void clear() {
             fields = 0;
         }
-
-        inline bool isDirty() {
-            return fields != 0;
-        }
     } mAccumulator;
 
     bool mDown;
@@ -804,7 +796,8 @@
             FIELD_ABS_MT_WIDTH_MAJOR = 16,
             FIELD_ABS_MT_WIDTH_MINOR = 32,
             FIELD_ABS_MT_ORIENTATION = 64,
-            FIELD_ABS_MT_TRACKING_ID = 128
+            FIELD_ABS_MT_TRACKING_ID = 128,
+            FIELD_ABS_MT_PRESSURE = 256,
         };
 
         uint32_t pointerCount;
@@ -819,6 +812,7 @@
             int32_t absMTWidthMinor;
             int32_t absMTOrientation;
             int32_t absMTTrackingId;
+            int32_t absMTPressure;
 
             inline void clear() {
                 fields = 0;
@@ -829,10 +823,6 @@
             pointerCount = 0;
             pointers[0].clear();
         }
-
-        inline bool isDirty() {
-            return pointerCount != 0;
-        }
     } mAccumulator;
 
     void initialize();
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 124f7b3..891661d 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -60,7 +60,6 @@
 #define ID_MASK  0x0000ffff
 #define SEQ_MASK 0x7fff0000
 #define SEQ_SHIFT 16
-#define id_to_index(id)         ((id&ID_MASK)+1)
 
 #ifndef ABS_MT_TOUCH_MAJOR
 #define ABS_MT_TOUCH_MAJOR      0x30    /* Major axis of touching ellipse */
@@ -87,7 +86,7 @@
 
 EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
     : id(_id), path(_path), name(name), classes(0)
-    , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
+    , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), fd(-1), next(NULL) {
 }
 
 EventHub::device_t::~device_t() {
@@ -100,6 +99,7 @@
     , mDevicesById(0), mNumDevicesById(0)
     , mOpeningDevices(0), mClosingDevices(0)
     , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
+    , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0)
 {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 #ifdef EV_SW
@@ -151,9 +151,9 @@
 
     struct input_absinfo info;
 
-    if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) {
+    if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
         LOGW("Error reading absolute controller %d for device %s fd %d\n",
-             axis, device->name.string(), mFDs[id_to_index(device->id)].fd);
+             axis, device->name.string(), device->fd);
         return -errno;
     }
 
@@ -182,7 +182,7 @@
 int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
     uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
-    if (ioctl(mFDs[id_to_index(device->id)].fd,
+    if (ioctl(device->fd,
                EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
         return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
     }
@@ -205,8 +205,7 @@
 
     uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
-    if (ioctl(mFDs[id_to_index(device->id)].fd,
-               EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
+    if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
         #if 0
         for (size_t i=0; i<=KEY_MAX; i++) {
             LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
@@ -242,7 +241,7 @@
 int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
     uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
     memset(sw_bitmask, 0, sizeof(sw_bitmask));
-    if (ioctl(mFDs[id_to_index(device->id)].fd,
+    if (ioctl(device->fd,
                EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
         return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
     }
@@ -343,13 +342,6 @@
     outEvent->value = 0;
     outEvent->when = 0;
 
-    status_t err;
-
-    int i;
-    int res;
-    int pollres;
-    struct input_event iev;
-
     // Note that we only allow one caller to getEvent(), so don't need
     // to do locking here...  only when adding/removing devices.
 
@@ -358,9 +350,8 @@
         mOpened = true;
     }
 
-    while(1) {
-
-        // First, report any devices that had last been added/removed.
+    for (;;) {
+        // Report any devices that had last been added/removed.
         if (mClosingDevices != NULL) {
             device_t* device = mClosingDevices;
             LOGV("Reporting device closed: id=0x%x, name=%s\n",
@@ -390,77 +381,96 @@
             return true;
         }
 
-        release_wake_lock(WAKE_LOCK_ID);
+        // Grab the next input event.
+        for (;;) {
+            // Consume buffered input events, if any.
+            if (mInputBufferIndex < mInputBufferCount) {
+                const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
+                const device_t* device = mDevices[mInputDeviceIndex];
 
-        pollres = poll(mFDs, mFDCount, -1);
-
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
-
-        if (pollres <= 0) {
-            if (errno != EINTR) {
-                LOGW("select failed (errno=%d)\n", errno);
-                usleep(100000);
-            }
-            continue;
-        }
-
-        //printf("poll %d, returned %d\n", mFDCount, pollres);
-
-        // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
-        for(i = 1; i < mFDCount; i++) {
-            if(mFDs[i].revents) {
-                LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
-                if(mFDs[i].revents & POLLIN) {
-                    res = read(mFDs[i].fd, &iev, sizeof(iev));
-                    if (res == sizeof(iev)) {
-                        device_t* device = mDevices[i];
-                        LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
-                             device->path.string(),
-                             (int) iev.time.tv_sec, (int) iev.time.tv_usec,
-                             iev.type, iev.code, iev.value);
-                        if (device->id == mFirstKeyboardId) {
-                            outEvent->deviceId = 0;
-                        } else {
-                            outEvent->deviceId = device->id;
-                        }
-                        outEvent->type = iev.type;
-                        outEvent->scanCode = iev.code;
-                        if (iev.type == EV_KEY) {
-                            err = device->layoutMap->map(iev.code,
-                                    & outEvent->keyCode, & outEvent->flags);
-                            LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
-                                iev.code, outEvent->keyCode, outEvent->flags, err);
-                            if (err != 0) {
-                                outEvent->keyCode = AKEYCODE_UNKNOWN;
-                                outEvent->flags = 0;
-                            }
-                        } else {
-                            outEvent->keyCode = iev.code;
-                        }
-                        outEvent->value = iev.value;
-
-                        // Use an event timestamp in the same timebase as
-                        // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
-                        // as expected by the rest of the system.
-                        outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
-                        return true;
-                    } else {
-                        if (res<0) {
-                            LOGW("could not get event (errno=%d)", errno);
-                        } else {
-                            LOGE("could not get event (wrong size: %d)", res);
-                        }
-                        continue;
+                LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
+                     (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
+                if (device->id == mFirstKeyboardId) {
+                    outEvent->deviceId = 0;
+                } else {
+                    outEvent->deviceId = device->id;
+                }
+                outEvent->type = iev.type;
+                outEvent->scanCode = iev.code;
+                if (iev.type == EV_KEY) {
+                    status_t err = device->layoutMap->map(iev.code,
+                            & outEvent->keyCode, & outEvent->flags);
+                    LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
+                        iev.code, outEvent->keyCode, outEvent->flags, err);
+                    if (err != 0) {
+                        outEvent->keyCode = AKEYCODE_UNKNOWN;
+                        outEvent->flags = 0;
                     }
+                } else {
+                    outEvent->keyCode = iev.code;
+                }
+                outEvent->value = iev.value;
+
+                // Use an event timestamp in the same timebase as
+                // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
+                // as expected by the rest of the system.
+                outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
+                return true;
+            }
+
+            // Finish reading all events from devices identified in previous poll().
+            // This code assumes that mInputDeviceIndex is initially 0 and that the
+            // revents member of pollfd is initialized to 0 when the device is first added.
+            // Since mFDs[0] is used for inotify, we process regular events starting at index 1.
+            mInputDeviceIndex += 1;
+            if (mInputDeviceIndex >= mFDCount) {
+                mInputDeviceIndex = 0;
+                break;
+            }
+
+            const struct pollfd &pfd = mFDs[mInputDeviceIndex];
+            if (pfd.revents & POLLIN) {
+                int32_t readSize = read(pfd.fd, mInputBufferData,
+                        sizeof(struct input_event) * INPUT_BUFFER_SIZE);
+                if (readSize < 0) {
+                    if (errno != EAGAIN && errno != EINTR) {
+                        LOGW("could not get event (errno=%d)", errno);
+                    }
+                } else if ((readSize % sizeof(struct input_event)) != 0) {
+                    LOGE("could not get event (wrong size: %d)", readSize);
+                } else {
+                    mInputBufferCount = readSize / sizeof(struct input_event);
+                    mInputBufferIndex = 0;
                 }
             }
         }
-        
+
         // read_notify() will modify mFDs and mFDCount, so this must be done after
         // processing all other events.
         if(mFDs[0].revents & POLLIN) {
             read_notify(mFDs[0].fd);
         }
+
+        // Poll for events.  Mind the wake lock dance!
+        // We hold a wake lock at all times except during poll().  This works due to some
+        // subtle choreography.  When a device driver has pending (unread) events, it acquires
+        // a kernel wake lock.  However, once the last pending event has been read, the device
+        // driver will release the kernel wake lock.  To prevent the system from going to sleep
+        // when this happens, the EventHub holds onto its own user wake lock while the client
+        // is processing events.  Thus the system can only sleep if there are no events
+        // pending or currently being processed.
+        release_wake_lock(WAKE_LOCK_ID);
+
+        int pollResult = poll(mFDs, mFDCount, -1);
+
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
+        if (pollResult <= 0) {
+            if (errno != EINTR) {
+                LOGW("select failed (errno=%d)\n", errno);
+                usleep(100000);
+            }
+        }
     }
 }
 
@@ -478,6 +488,7 @@
     mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
     mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
     mFDs[0].events = POLLIN;
+    mFDs[0].revents = 0;
     mDevices[0] = NULL;
 #ifdef HAVE_INOTIFY
     mFDs[0].fd = inotify_init();
@@ -570,7 +581,6 @@
         if (strcmp(name, test) == 0) {
             LOGI("ignoring event id %s driver %s\n", deviceName, test);
             close(fd);
-            fd = -1;
             return -1;
         }
     }
@@ -584,6 +594,12 @@
         idstr[0] = '\0';
     }
 
+    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
+        LOGE("Error %d making device file descriptor non-blocking.", errno);
+        close(fd);
+        return -1;
+    }
+
     int devid = 0;
     while (devid < mNumDevicesById) {
         if (mDevicesById[devid].device == NULL) {
@@ -638,8 +654,10 @@
         return -1;
     }
 
+    device->fd = fd;
     mFDs[mFDCount].fd = fd;
     mFDs[mFDCount].events = POLLIN;
+    mFDs[mFDCount].revents = 0;
 
     // Figure out the kinds of events the device reports.
     
@@ -794,6 +812,14 @@
                 device->id, name, propName, keylayoutFilename);
     }
 
+    // If the device isn't recognized as something we handle, don't monitor it.
+    if (device->classes == 0) {
+        LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid);
+        close(fd);
+        delete device;
+        return -1;
+    }
+
     LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
          deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
          
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b53f140..13030b5 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -433,8 +433,7 @@
     for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
         const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
 
-        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(
-                inputTarget.inputChannel->getReceivePipeFd());
+        ssize_t connectionIndex = getConnectionIndex(inputTarget.inputChannel);
         if (connectionIndex >= 0) {
             sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
             prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
@@ -1367,12 +1366,10 @@
     LOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().string());
 #endif
 
-    int receiveFd;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        if (mConnectionsByReceiveFd.indexOfKey(receiveFd) >= 0) {
+        if (getConnectionIndex(inputChannel) >= 0) {
             LOGW("Attempted to register already registered input channel '%s'",
                     inputChannel->getName().string());
             return BAD_VALUE;
@@ -1386,12 +1383,13 @@
             return status;
         }
 
+        int32_t receiveFd = inputChannel->getReceivePipeFd();
         mConnectionsByReceiveFd.add(receiveFd, connection);
 
+        mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+
         runCommandsLockedInterruptible();
     } // release lock
-
-    mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
     return OK;
 }
 
@@ -1400,12 +1398,10 @@
     LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
 #endif
 
-    int32_t receiveFd;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
+        ssize_t connectionIndex = getConnectionIndex(inputChannel);
         if (connectionIndex < 0) {
             LOGW("Attempted to unregister already unregistered input channel '%s'",
                     inputChannel->getName().string());
@@ -1417,20 +1413,32 @@
 
         connection->status = Connection::STATUS_ZOMBIE;
 
+        mPollLoop->removeCallback(inputChannel->getReceivePipeFd());
+
         nsecs_t currentTime = now();
         abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
 
         runCommandsLockedInterruptible();
     } // release lock
 
-    mPollLoop->removeCallback(receiveFd);
-
     // Wake the poll loop because removing the connection may have changed the current
     // synchronization state.
     mPollLoop->wake();
     return OK;
 }
 
+ssize_t InputDispatcher::getConnectionIndex(const sp<InputChannel>& inputChannel) {
+    ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
+    if (connectionIndex >= 0) {
+        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        if (connection->inputChannel.get() == inputChannel.get()) {
+            return connectionIndex;
+        }
+    }
+
+    return -1;
+}
+
 void InputDispatcher::activateConnectionLocked(Connection* connection) {
     for (size_t i = 0; i < mActiveConnections.size(); i++) {
         if (mActiveConnections.itemAt(i) == connection) {
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 5f5a4ac..6f042ec 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -945,7 +945,6 @@
         mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
         mAccumulator.btnMouse = false;
         sync(when);
-        mAccumulator.clear();
     }
 
     InputMapper::reset();
@@ -958,9 +957,9 @@
         case BTN_MOUSE:
             mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
             mAccumulator.btnMouse = rawEvent->value != 0;
-
+            // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and
+            // we need to ensure that we report the up/down promptly.
             sync(rawEvent->when);
-            mAccumulator.clear();
             break;
         }
         break;
@@ -981,10 +980,7 @@
     case EV_SYN:
         switch (rawEvent->scanCode) {
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -992,13 +988,17 @@
 }
 
 void TrackballInputMapper::sync(nsecs_t when) {
+    uint32_t fields = mAccumulator.fields;
+    if (fields == 0) {
+        return; // no new state changes, so nothing to do
+    }
+
     int motionEventAction;
     PointerCoords pointerCoords;
     nsecs_t downTime;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        uint32_t fields = mAccumulator.fields;
         bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
 
         if (downChanged) {
@@ -1061,6 +1061,8 @@
     } // release lock
 
     applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
+
+    mAccumulator.clear();
 }
 
 void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
@@ -2380,8 +2382,8 @@
     mDown = false;
     mX = 0;
     mY = 0;
-    mPressure = 0;
-    mSize = 0;
+    mPressure = 1; // default to 1 for devices that don't report pressure
+    mSize = 0; // default to 0 for devices that don't report size
 }
 
 void SingleTouchInputMapper::reset() {
@@ -2397,9 +2399,9 @@
         case BTN_TOUCH:
             mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;
             mAccumulator.btnTouch = rawEvent->value != 0;
-
-            sync(rawEvent->when);
-            mAccumulator.clear();
+            // Don't sync immediately.  Wait until the next SYN_REPORT since we might
+            // not have received valid position information yet.  This logic assumes that
+            // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
             break;
         }
         break;
@@ -2428,10 +2430,7 @@
     case EV_SYN:
         switch (rawEvent->scanCode) {
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -2439,9 +2438,10 @@
 }
 
 void SingleTouchInputMapper::sync(nsecs_t when) {
-    /* Update device state */
-
     uint32_t fields = mAccumulator.fields;
+    if (fields == 0) {
+        return; // no new state changes, so nothing to do
+    }
 
     if (fields & Accumulator::FIELD_BTN_TOUCH) {
         mDown = mAccumulator.btnTouch;
@@ -2472,8 +2472,8 @@
         mCurrentTouch.pointers[0].y = mY;
         mCurrentTouch.pointers[0].pressure = mPressure;
         mCurrentTouch.pointers[0].size = mSize;
-        mCurrentTouch.pointers[0].touchMajor = mPressure;
-        mCurrentTouch.pointers[0].touchMinor = mPressure;
+        mCurrentTouch.pointers[0].touchMajor = mSize;
+        mCurrentTouch.pointers[0].touchMinor = mSize;
         mCurrentTouch.pointers[0].toolMajor = mSize;
         mCurrentTouch.pointers[0].toolMinor = mSize;
         mCurrentTouch.pointers[0].orientation = 0;
@@ -2482,6 +2482,8 @@
     }
 
     syncTouch(when, true);
+
+    mAccumulator.clear();
 }
 
 void SingleTouchInputMapper::configureAxes() {
@@ -2494,8 +2496,8 @@
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size);
 
-    mAxes.touchMajor = mAxes.pressure;
-    mAxes.touchMinor = mAxes.pressure;
+    mAxes.touchMajor = mAxes.size;
+    mAxes.touchMinor = mAxes.size;
     mAxes.toolMajor = mAxes.size;
     mAxes.toolMinor = mAxes.size;
 }
@@ -2585,10 +2587,7 @@
         }
 
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -2598,11 +2597,7 @@
 void MultiTouchInputMapper::sync(nsecs_t when) {
     static const uint32_t REQUIRED_FIELDS =
             Accumulator::FIELD_ABS_MT_POSITION_X
-            | Accumulator::FIELD_ABS_MT_POSITION_Y
-            | Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
-            | Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
-
-    /* Update device state */
+            | Accumulator::FIELD_ABS_MT_POSITION_Y;
 
     uint32_t inCount = mAccumulator.pointerCount;
     uint32_t outCount = 0;
@@ -2611,53 +2606,76 @@
     mCurrentTouch.clear();
 
     for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
-        uint32_t fields = mAccumulator.pointers[inIndex].fields;
+        const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex];
+        uint32_t fields = inPointer.fields;
 
         if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
-#if DEBUG_POINTERS
-            LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
-                    inIndex, fields);
-            continue;
-#endif
-        }
-
-        if (mAccumulator.pointers[inIndex].absMTTouchMajor <= 0) {
-            // Pointer is not down.  Drop it.
+            // Some drivers send empty MT sync packets without X / Y to indicate a pointer up.
+            // Drop this finger.
             continue;
         }
 
-        mCurrentTouch.pointers[outCount].x = mAccumulator.pointers[inIndex].absMTPositionX;
-        mCurrentTouch.pointers[outCount].y = mAccumulator.pointers[inIndex].absMTPositionY;
+        PointerData& outPointer = mCurrentTouch.pointers[outCount];
+        outPointer.x = inPointer.absMTPositionX;
+        outPointer.y = inPointer.absMTPositionY;
 
-        mCurrentTouch.pointers[outCount].touchMajor =
-                mAccumulator.pointers[inIndex].absMTTouchMajor;
-        mCurrentTouch.pointers[outCount].touchMinor =
-                (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
-                ? mAccumulator.pointers[inIndex].absMTTouchMinor
-                        : mAccumulator.pointers[inIndex].absMTTouchMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) {
+            int32_t value = inPointer.absMTTouchMajor;
+            if (value <= 0) {
+                // Some devices send sync packets with X / Y but with a 0 touch major to indicate
+                // a pointer up.  Drop this finger.
+                continue;
+            }
+            outPointer.touchMajor = inPointer.absMTTouchMajor;
+        } else {
+            outPointer.touchMajor = 0;
+        }
 
-        mCurrentTouch.pointers[outCount].toolMajor =
-                mAccumulator.pointers[inIndex].absMTWidthMajor;
-        mCurrentTouch.pointers[outCount].toolMinor =
-                (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
-                ? mAccumulator.pointers[inIndex].absMTWidthMinor
-                        : mAccumulator.pointers[inIndex].absMTWidthMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) {
+            outPointer.touchMinor = inPointer.absMTTouchMinor;
+        } else {
+            outPointer.touchMinor = outPointer.touchMajor;
+        }
 
-        mCurrentTouch.pointers[outCount].orientation =
-                (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
-                ? mAccumulator.pointers[inIndex].absMTOrientation : 0;
+        if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) {
+            outPointer.toolMajor = inPointer.absMTWidthMajor;
+        } else {
+            outPointer.toolMajor = outPointer.touchMajor;
+        }
 
-        // Derive an approximation of pressure and size.
-        // FIXME assignment of pressure may be incorrect, probably better to let
-        // pressure = touch / width.  Later on we pass width to MotionEvent as a size, which
-        // isn't quite right either.  Should be using touch for that.
-        mCurrentTouch.pointers[outCount].pressure = mAccumulator.pointers[inIndex].absMTTouchMajor;
-        mCurrentTouch.pointers[outCount].size = mAccumulator.pointers[inIndex].absMTWidthMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) {
+            outPointer.toolMinor = inPointer.absMTWidthMinor;
+        } else {
+            outPointer.toolMinor = outPointer.toolMajor;
+        }
+
+        if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) {
+            outPointer.orientation = inPointer.absMTOrientation;
+        } else {
+            outPointer.orientation = 0;
+        }
+
+        if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
+            outPointer.pressure = inPointer.absMTPressure;
+        } else {
+            // Derive an approximation of pressure.
+            // FIXME Traditionally we have just passed a normalized value based on
+            //       ABS_MT_TOUCH_MAJOR as an estimate of pressure but the result is not
+            //       very meaningful, particularly on large displays.  We should probably let
+            //       pressure = touch_major / tool_major but it is unclear whether that will
+            //       break applications.
+            outPointer.pressure = outPointer.touchMajor;
+        }
+
+        // Size is an alias for a normalized tool width.
+        // FIXME Normalized tool width doesn't actually make much sense since it literally
+        //       means the approaching contact major axis is divided by its full range as
+        //       reported by the driver.  On a large display this could produce very small values.
+        outPointer.size = outPointer.toolMajor;
 
         if (havePointerIds) {
-            if (fields & Accumulator::
-                    FIELD_ABS_MT_TRACKING_ID) {
-                uint32_t id = uint32_t(mAccumulator.pointers[inIndex].absMTTrackingId);
+            if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
+                uint32_t id = uint32_t(inPointer.absMTTrackingId);
 
                 if (id > MAX_POINTER_ID) {
 #if DEBUG_POINTERS
@@ -2668,7 +2686,7 @@
                     havePointerIds = false;
                 }
                 else {
-                    mCurrentTouch.pointers[outCount].id = id;
+                    outPointer.id = id;
                     mCurrentTouch.idToIndex[id] = outCount;
                     mCurrentTouch.idBits.markBit(id);
                 }
@@ -2683,6 +2701,8 @@
     mCurrentTouch.pointerCount = outCount;
 
     syncTouch(when, havePointerIds);
+
+    mAccumulator.clear();
 }
 
 void MultiTouchInputMapper::configureAxes() {
@@ -2697,6 +2717,7 @@
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation);
+    getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mAxes.pressure);
 
     if (! mAxes.touchMinor.valid) {
         mAxes.touchMinor = mAxes.touchMajor;
@@ -2706,7 +2727,10 @@
         mAxes.toolMinor = mAxes.toolMajor;
     }
 
-    mAxes.pressure = mAxes.touchMajor;
+    if (! mAxes.pressure.valid) {
+        mAxes.pressure = mAxes.touchMajor;
+    }
+
     mAxes.size = mAxes.toolMajor;
 }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6af3a7f..12a1e6e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1273,6 +1273,14 @@
     hexdump(csd, csd_size);
 #endif
 
+    if (csd_size == 0) {
+        // There's no further information, i.e. no codec specific data
+        // Let's assume that the information provided in the mpeg4 headers
+        // is accurate and hope for the best.
+
+        return OK;
+    }
+
     if (csd_size < 2) {
         return ERROR_MALFORMED;
     }
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index b699d8f..9630092 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -158,7 +158,7 @@
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
         off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll;
-        LOGI("seeking to offset %ld", pos);
+        LOGV("seeking to offset %ld", pos);
 
         if (mExtractor->mImpl->seekToOffset(pos) != OK) {
             return ERROR_END_OF_STREAM;
@@ -267,7 +267,7 @@
     uint8_t header[27];
     if (mSource->readAt(offset, header, sizeof(header))
             < (ssize_t)sizeof(header)) {
-        LOGE("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
+        LOGV("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
 
         return ERROR_IO;
     }
@@ -384,7 +384,7 @@
                     packetSize);
 
             if (n < (ssize_t)packetSize) {
-                LOGE("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
+                LOGV("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
                 return ERROR_IO;
             }
 
@@ -418,7 +418,7 @@
                 buffer = NULL;
             }
 
-            LOGE("readPage returned %ld", n);
+            LOGV("readPage returned %ld", n);
 
             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
         }
diff --git a/packages/DefaultContainerService/res/values-cs/strings.xml b/packages/DefaultContainerService/res/values-cs/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-cs/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-da/strings.xml b/packages/DefaultContainerService/res/values-da/strings.xml
new file mode 100644
index 0000000..5243028
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-da/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Hjælp til pakkeadgang"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-de/strings.xml b/packages/DefaultContainerService/res/values-de/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-de/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-el/strings.xml b/packages/DefaultContainerService/res/values-el/strings.xml
new file mode 100644
index 0000000..a4d8144
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-el/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"ΒοηθฯŒς πρฯŒσβασης πακฮญτου"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-es-rUS/strings.xml b/packages/DefaultContainerService/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..670c2c5
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-es-rUS/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Asist. p/acceder al paq."</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-es/strings.xml b/packages/DefaultContainerService/res/values-es/strings.xml
new file mode 100644
index 0000000..022c461
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-es/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Ayudante acceso a paquete"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-fr/strings.xml b/packages/DefaultContainerService/res/values-fr/strings.xml
new file mode 100644
index 0000000..5c458bc
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-fr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Aide accès au package"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-it/strings.xml b/packages/DefaultContainerService/res/values-it/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-it/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ja/strings.xml b/packages/DefaultContainerService/res/values-ja/strings.xml
new file mode 100644
index 0000000..2f57e4e
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ja/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"ใƒ‘ใƒƒใ‚ฑใƒผใ‚ธใ‚ขใ‚ฏใ‚ปใ‚นๆ”ฏๆดใƒ„ใƒผใƒซ"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ko/strings.xml b/packages/DefaultContainerService/res/values-ko/strings.xml
new file mode 100644
index 0000000..0304972
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ko/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"ํŒจํ‚ค์ง€ ์•ก์„ธ์Šค ๋„์›€๋ง"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-nb/strings.xml b/packages/DefaultContainerService/res/values-nb/strings.xml
new file mode 100644
index 0000000..637f54d
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-nb/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Hjelpeprogram for pakketilgang"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-nl/strings.xml b/packages/DefaultContainerService/res/values-nl/strings.xml
new file mode 100644
index 0000000..9ece040
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-nl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Helper voor pakkettoegang"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-pl/strings.xml b/packages/DefaultContainerService/res/values-pl/strings.xml
new file mode 100644
index 0000000..216d715
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-pl/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Package Access Helper"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-pt-rPT/strings.xml b/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..5c03669
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-pt-rPT/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Ajuda p/ aceder pacotes"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-pt/strings.xml b/packages/DefaultContainerService/res/values-pt/strings.xml
new file mode 100644
index 0000000..5fbd949
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-pt/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Assistente de pacote"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-ru/strings.xml b/packages/DefaultContainerService/res/values-ru/strings.xml
new file mode 100644
index 0000000..ccb0c53
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-ru/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"ะœะฐัั‚ะตั€ ะดะพัั‚ัƒะฟะฐ ะบ ะฟะฐะบะตั‚ะฐะผ"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-sv/strings.xml b/packages/DefaultContainerService/res/values-sv/strings.xml
new file mode 100644
index 0000000..097a709
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-sv/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Hjälp med paketåtkomst"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-tr/strings.xml b/packages/DefaultContainerService/res/values-tr/strings.xml
new file mode 100644
index 0000000..12ea674
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-tr/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"Paket EriลŸim Yardฤฑmcฤฑsฤฑ"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-zh-rCN/strings.xml b/packages/DefaultContainerService/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..65928b1
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-zh-rCN/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"่ฝฏไปถๅŒ…่ฎฟ้—ฎๅธฎๅŠฉ็จ‹ๅบ"</string>
+</resources>
diff --git a/packages/DefaultContainerService/res/values-zh-rTW/strings.xml b/packages/DefaultContainerService/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..9a43509
--- /dev/null
+++ b/packages/DefaultContainerService/res/values-zh-rTW/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name" msgid="4841491635055379553">"ๅฅ—ไปถๅญ˜ๅ–่ผ”ๅŠฉ็จ‹ๅผ"</string>
+</resources>
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 509c789..af4d7e4 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -116,6 +116,8 @@
 
     private final LockList mLocks = new LockList();
     // some wifi lock statistics
+    private int mFullHighPerfLocksAcquired;
+    private int mFullHighPerfLocksReleased;
     private int mFullLocksAcquired;
     private int mFullLocksReleased;
     private int mScanLocksAcquired;
@@ -1782,8 +1784,8 @@
         msg.sendToTarget();
     }
 
-    private void sendStartMessage(boolean scanOnlyMode) {
-        Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget();
+    private void sendStartMessage(int lockMode) {
+        Message.obtain(mWifiHandler, MESSAGE_START_WIFI, lockMode, 0).sendToTarget();
     }
 
     private void sendAccessPointMessage(boolean enable, WifiConfiguration wifiConfig, int uid) {
@@ -1801,12 +1803,15 @@
         boolean wifiEnabled = getPersistedWifiEnabled();
         boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden;
         boolean lockHeld = mLocks.hasLocks();
-        int strongestLockMode;
+        int strongestLockMode = WifiManager.WIFI_MODE_FULL;
         boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
-        if (mDeviceIdle && lockHeld) {
+
+        if (lockHeld) {
             strongestLockMode = mLocks.getStrongestLockMode();
-        } else {
+        }
+        /* If device is not idle, lockmode cannot be scan only */
+        if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) {
             strongestLockMode = WifiManager.WIFI_MODE_FULL;
         }
 
@@ -1827,7 +1832,7 @@
                     sWakeLock.acquire();
                     sendEnableMessage(true, false, mLastEnableUid);
                     sWakeLock.acquire();
-                    sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
+                    sendStartMessage(strongestLockMode);
                 } else if (!mWifiStateTracker.isDriverStopped()) {
                     int wakeLockTimeout =
                             Settings.Secure.getInt(
@@ -1905,8 +1910,10 @@
                     break;
 
                 case MESSAGE_START_WIFI:
-                    mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0);
+                    mWifiStateTracker.setScanOnlyMode(msg.arg1 == WifiManager.WIFI_MODE_SCAN_ONLY);
                     mWifiStateTracker.restart();
+                    mWifiStateTracker.setHighPerfMode(msg.arg1 ==
+                            WifiManager.WIFI_MODE_FULL_HIGH_PERF);
                     sWakeLock.release();
                     break;
 
@@ -1986,8 +1993,10 @@
         }
         pw.println();
         pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
+                mFullHighPerfLocksAcquired + " full high perf, " +
                 mScanLocksAcquired + " scan");
         pw.println("Locks released: " + mFullLocksReleased + " full, " +
+                mFullHighPerfLocksReleased + " full high perf, " +
                 mScanLocksReleased + " scan");
         pw.println();
         pw.println("Locks held:");
@@ -2042,11 +2051,15 @@
             if (mList.isEmpty()) {
                 return WifiManager.WIFI_MODE_FULL;
             }
-            for (WifiLock l : mList) {
-                if (l.mMode == WifiManager.WIFI_MODE_FULL) {
-                    return WifiManager.WIFI_MODE_FULL;
-                }
+
+            if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
+                return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
             }
+
+            if (mFullLocksAcquired > mFullLocksReleased) {
+                return WifiManager.WIFI_MODE_FULL;
+            }
+
             return WifiManager.WIFI_MODE_SCAN_ONLY;
         }
 
@@ -2085,7 +2098,11 @@
 
     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
-        if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
+        if (lockMode != WifiManager.WIFI_MODE_FULL &&
+                lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
+                lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
+            Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
+            if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
             return false;
         }
         WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
@@ -2107,6 +2124,12 @@
                 ++mFullLocksAcquired;
                 mBatteryStats.noteFullWifiLockAcquired(uid);
                 break;
+            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+                ++mFullHighPerfLocksAcquired;
+                /* Treat high power as a full lock for battery stats */
+                mBatteryStats.noteFullWifiLockAcquired(uid);
+                break;
+
             case WifiManager.WIFI_MODE_SCAN_ONLY:
                 ++mScanLocksAcquired;
                 mBatteryStats.noteScanWifiLockAcquired(uid);
@@ -2146,6 +2169,10 @@
                         ++mFullLocksReleased;
                         mBatteryStats.noteFullWifiLockReleased(uid);
                         break;
+                    case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
+                        ++mFullHighPerfLocksReleased;
+                        mBatteryStats.noteFullWifiLockReleased(uid);
+                        break;
                     case WifiManager.WIFI_MODE_SCAN_ONLY:
                         ++mScanLocksReleased;
                         mBatteryStats.noteScanWifiLockReleased(uid);
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index ebe71ab..ba58b43 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -319,9 +319,9 @@
     bool isScreenOn();
     bool isScreenBright();
 
-    // Weak references to all currently registered input channels by receive fd.
+    // Weak references to all currently registered input channels by connection pointer.
     Mutex mInputChannelRegistryLock;
-    KeyedVector<int, jweak> mInputChannelObjWeakByReceiveFd;
+    KeyedVector<InputChannel*, jweak> mInputChannelObjWeakTable;
 
     jobject getInputChannelObjLocal(JNIEnv* env, const sp<InputChannel>& inputChannel);
 
@@ -509,8 +509,7 @@
     {
         AutoMutex _l(mInputChannelRegistryLock);
 
-        ssize_t index = mInputChannelObjWeakByReceiveFd.indexOfKey(
-                inputChannel->getReceivePipeFd());
+        ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get());
         if (index >= 0) {
             LOGE("Input channel object '%s' has already been registered",
                     inputChannel->getName().string());
@@ -518,8 +517,7 @@
             goto DeleteWeakRef;
         }
 
-        mInputChannelObjWeakByReceiveFd.add(inputChannel->getReceivePipeFd(),
-                inputChannelObjWeak);
+        mInputChannelObjWeakTable.add(inputChannel.get(), inputChannelObjWeak);
     }
 
     status = mInputManager->registerInputChannel(inputChannel);
@@ -534,7 +532,7 @@
     // Failed!
     {
         AutoMutex _l(mInputChannelRegistryLock);
-        mInputChannelObjWeakByReceiveFd.removeItem(inputChannel->getReceivePipeFd());
+        mInputChannelObjWeakTable.removeItem(inputChannel.get());
     }
 
 DeleteWeakRef:
@@ -548,16 +546,15 @@
     {
         AutoMutex _l(mInputChannelRegistryLock);
 
-        ssize_t index = mInputChannelObjWeakByReceiveFd.indexOfKey(
-                inputChannel->getReceivePipeFd());
+        ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get());
         if (index < 0) {
             LOGE("Input channel object '%s' is not currently registered",
                     inputChannel->getName().string());
             return INVALID_OPERATION;
         }
 
-        inputChannelObjWeak = mInputChannelObjWeakByReceiveFd.valueAt(index);
-        mInputChannelObjWeakByReceiveFd.removeItemsAt(index);
+        inputChannelObjWeak = mInputChannelObjWeakTable.valueAt(index);
+        mInputChannelObjWeakTable.removeItemsAt(index);
     }
 
     env->DeleteWeakGlobalRef(inputChannelObjWeak);
@@ -572,13 +569,12 @@
     {
         AutoMutex _l(mInputChannelRegistryLock);
 
-        ssize_t index = mInputChannelObjWeakByReceiveFd.indexOfKey(
-                inputChannel->getReceivePipeFd());
+        ssize_t index = mInputChannelObjWeakTable.indexOfKey(inputChannel.get());
         if (index < 0) {
             return NULL;
         }
 
-        jweak inputChannelObjWeak = mInputChannelObjWeakByReceiveFd.valueAt(index);
+        jweak inputChannelObjWeak = mInputChannelObjWeakTable.valueAt(index);
         return env->NewLocalRef(inputChannelObjWeak);
     }
 }
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 79772ed..a14bfb5 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -5,7 +5,6 @@
     clz.cpp.arm \
     DisplayHardware/DisplayHardware.cpp \
     DisplayHardware/DisplayHardwareBase.cpp \
-    DisplayHardware/HWComposer.cpp \
     BlurFilter.cpp.arm \
     GLExtensions.cpp \
     Layer.cpp \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 166c528..2eac0a8 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -36,11 +36,11 @@
 
 #include "DisplayHardware/DisplayHardware.h"
 
+#include <hardware/copybit.h>
 #include <hardware/overlay.h>
 #include <hardware/gralloc.h>
 
 #include "GLExtensions.h"
-#include "HWComposer.h"
 
 using namespace android;
 
@@ -76,7 +76,7 @@
         const sp<SurfaceFlinger>& flinger,
         uint32_t dpy)
     : DisplayHardwareBase(flinger, dpy),
-      mFlags(0), mHwc(0)
+      mFlags(0)
 {
     init(dpy);
 }
@@ -262,17 +262,6 @@
 
     // Unbind the context from this thread
     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-
-    // initialize the H/W composer
-    mHwc = new HWComposer();
-    if (mHwc->initCheck() == NO_ERROR) {
-        mHwc->setFrameBuffer(mDisplay, mSurface);
-    }
-}
-
-HWComposer& DisplayHardware::getHwComposer() const {
-    return *mHwc;
 }
 
 /*
@@ -328,12 +317,7 @@
     }
     
     mPageFlipCount++;
-
-    if (mHwc->initCheck() == NO_ERROR) {
-        mHwc->commit();
-    } else {
-        eglSwapBuffers(dpy, surface);
-    }
+    eglSwapBuffers(dpy, surface);
     checkEGLErrors("eglSwapBuffers");
 
     // for debugging
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index f2cfd2d..66bf521 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -34,11 +34,12 @@
 #include "DisplayHardware/DisplayHardwareBase.h"
 
 struct overlay_control_device_t;
+struct framebuffer_device_t;
+struct copybit_image_t;
 
 namespace android {
 
 class FramebufferNativeWindow;
-class HWComposer;
 
 class DisplayHardware : public DisplayHardwareBase
 {
@@ -79,9 +80,6 @@
     uint32_t getPageFlipCount() const;
     EGLDisplay getEGLDisplay() const { return mDisplay; }
     overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
-
-    // Hardware Composer
-    HWComposer& getHwComposer() const;
     
     status_t compositionComplete() const;
     
@@ -109,8 +107,6 @@
     GLint           mMaxViewportDims;
     GLint           mMaxTextureSize;
     
-    HWComposer*     mHwc;
-
     sp<FramebufferNativeWindow> mNativeWindow;
     overlay_control_device_t* mOverlayEngine;
 };
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
deleted file mode 100644
index 0291d78..0000000
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ /dev/null
@@ -1,99 +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.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-
-#include <hardware/hardware.h>
-
-#include <cutils/log.h>
-
-#include <EGL/egl.h>
-
-#include "HWComposer.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-HWComposer::HWComposer()
-    : mModule(0), mHwc(0), mList(0), mCapacity(0),
-      mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
-{
-    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
-    LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
-    if (err == 0) {
-        err = hwc_open(mModule, &mHwc);
-        LOGE_IF(err, "%s device failed to initialize (%s)",
-                HWC_HARDWARE_COMPOSER, strerror(-err));
-    }
-}
-
-HWComposer::~HWComposer() {
-    free(mList);
-    if (mHwc) {
-        hwc_close(mHwc);
-    }
-}
-
-status_t HWComposer::initCheck() const {
-    return mHwc ? NO_ERROR : NO_INIT;
-}
-
-void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
-    mDpy = (hwc_display_t)dpy;
-    mSur = (hwc_surface_t)sur;
-}
-
-status_t HWComposer::createWorkList(size_t numLayers) {
-    if (mHwc) {
-        if (!mList || mCapacity < numLayers) {
-            free(mList);
-            size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t);
-            mList = (hwc_layer_list_t*)malloc(size);
-            mCapacity = numLayers;
-        }
-        mList->flags = HWC_GEOMETRY_CHANGED;
-        mList->numHwLayers = numLayers;
-    }
-    return NO_ERROR;
-}
-
-status_t HWComposer::prepare() const {
-    int err = mHwc->prepare(mHwc, mList);
-    return (status_t)err;
-}
-
-status_t HWComposer::commit() const {
-    int err = mHwc->set(mHwc, mDpy, mSur, mList);
-    mList->flags &= ~HWC_GEOMETRY_CHANGED;
-    return (status_t)err;
-}
-
-size_t HWComposer::getNumLayers() const {
-    return mList ? mList->numHwLayers : 0;
-}
-
-hwc_layer_t* HWComposer::getLayers() const {
-    return mList ? mList->hwLayers : 0;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
deleted file mode 100644
index c5d5c2b..0000000
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ /dev/null
@@ -1,68 +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 ANDROID_SF_HWCOMPOSER_H
-#define ANDROID_SF_HWCOMPOSER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <EGL/egl.h>
-
-#include <hardware/hwcomposer.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class HWComposer
-{
-public:
-
-    HWComposer();
-    ~HWComposer();
-
-    status_t initCheck() const;
-
-    // tells the HAL what the framebuffer is
-    void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
-
-    // create a work list for numLayers layer
-    status_t createWorkList(size_t numLayers);
-
-    // Asks the HAL what it can do
-    status_t prepare() const;
-
-    // commits the list
-    status_t commit() const;
-
-
-    size_t getNumLayers() const;
-    hwc_layer_t* getLayers() const;
-
-private:
-    hw_module_t const*      mModule;
-    hwc_composer_device_t*  mHwc;
-    hwc_layer_list_t*       mList;
-    size_t                  mCapacity;
-    hwc_display_t           mDpy;
-    hwc_surface_t           mSur;
-};
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3720e1669..629d993 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -35,7 +35,6 @@
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
-#include "DisplayHardware/HWComposer.h"
 
 
 #define DEBUG_RESIZE    0
@@ -178,62 +177,6 @@
     return NO_ERROR;
 }
 
-void Layer::setGeometry(hwc_layer_t* hwcl)
-{
-    hwcl->compositionType = HWC_FRAMEBUFFER;
-    hwcl->hints = 0;
-    hwcl->flags = 0;
-    hwcl->transform = 0;
-    hwcl->blending = HWC_BLENDING_NONE;
-
-    // we can't do alpha-fade with the hwc HAL
-    const State& s(drawingState());
-    if (s.alpha < 0xFF) {
-        hwcl->flags = HWC_SKIP_LAYER;
-        return;
-    }
-
-    // we can only handle simple transformation
-    if (mOrientation & Transform::ROT_INVALID) {
-        hwcl->flags = HWC_SKIP_LAYER;
-        return;
-    }
-
-    hwcl->transform = mOrientation;
-
-    if (needsBlending()) {
-        hwcl->blending = mPremultipliedAlpha ?
-                HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
-    }
-
-    hwcl->displayFrame.left   = mTransformedBounds.left;
-    hwcl->displayFrame.top    = mTransformedBounds.top;
-    hwcl->displayFrame.right  = mTransformedBounds.right;
-    hwcl->displayFrame.bottom = mTransformedBounds.bottom;
-
-    hwcl->visibleRegionScreen.rects =
-            reinterpret_cast<hwc_rect_t const *>(
-                    visibleRegionScreen.getArray(
-                            &hwcl->visibleRegionScreen.numRects));
-}
-
-void Layer::setPerFrameData(hwc_layer_t* hwcl) {
-    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
-    if (buffer == NULL) {
-        // this situation can happen if we ran out of memory for instance.
-        // not much we can do. continue to use whatever texture was bound
-        // to this context.
-        hwcl->handle = NULL;
-        return;
-    }
-    hwcl->handle = const_cast<native_handle_t*>(buffer->handle);
-    // TODO: set the crop value properly
-    hwcl->sourceCrop.left   = 0;
-    hwcl->sourceCrop.top    = 0;
-    hwcl->sourceCrop.right  = buffer->width;
-    hwcl->sourceCrop.bottom = buffer->height;
-}
-
 void Layer::reloadTexture(const Region& dirty)
 {
     sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 188da6a..e1d283b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -68,8 +68,6 @@
     bool isFixedSize() const;
 
     // LayerBase interface
-    virtual void setGeometry(hwc_layer_t* hwcl);
-    virtual void setPerFrameData(hwc_layer_t* hwcl);
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 043d54d..91ac915 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -307,15 +307,6 @@
     }
 }
 
-void LayerBase::setGeometry(hwc_layer_t* hwcl) {
-    hwcl->flags |= HWC_SKIP_LAYER;
-}
-
-void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
-    hwcl->compositionType = HWC_FRAMEBUFFER;
-    hwcl->handle = NULL;
-}
-
 void LayerBase::draw(const Region& clip) const
 {
     // reset GL state
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index dd1cd05..22bf857 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -35,8 +35,6 @@
 
 #include <pixelflinger/pixelflinger.h>
 
-#include <hardware/hwcomposer.h>
-
 #include "Transform.h"
 
 namespace android {
@@ -110,10 +108,6 @@
 
     virtual const char* getTypeId() const { return "LayerBase"; }
 
-    virtual void setGeometry(hwc_layer_t* hwcl);
-
-    virtual void setPerFrameData(hwc_layer_t* hwcl);
-
     /**
      * draw - performs some global clipping optimizations
      * and calls onDraw().
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d257897..637ae48 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -52,7 +52,6 @@
 #include "SurfaceFlinger.h"
 
 #include "DisplayHardware/DisplayHardware.h"
-#include "DisplayHardware/HWComposer.h"
 
 /* ideally AID_GRAPHICS would be in a semi-public header
  * or there would be a way to map a user/group name to its id
@@ -77,7 +76,6 @@
         mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
         mDump("android.permission.DUMP"),
         mVisibleRegionsDirty(false),
-        mHwWorkListDirty(false),
         mDeferReleaseConsole(false),
         mFreezeDisplay(false),
         mFreezeCount(0),
@@ -370,11 +368,6 @@
     // post surfaces (if needed)
     handlePageFlip();
 
-    if (UNLIKELY(mHwWorkListDirty)) {
-        // build the h/w work list
-        handleWorkList();
-    }
-
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     if (LIKELY(hw.canDraw() && !isFrozen())) {
         // repaint the framebuffer (if needed)
@@ -450,7 +443,6 @@
         handleTransactionLocked(transactionFlags, ditchedLayers);
         mLastTransactionTime = systemTime() - now;
         mDebugInTransaction = 0;
-        mHwWorkListDirty = true;
         // here the transaction has been committed
     }
 
@@ -458,7 +450,6 @@
      * Clean-up all layers that went away
      * (do this without the lock held)
      */
-
     const size_t count = ditchedLayers.size();
     for (size_t i=0 ; i<count ; i++) {
         if (ditchedLayers[i] != 0) {
@@ -692,8 +683,8 @@
 void SurfaceFlinger::handlePageFlip()
 {
     bool visibleRegions = mVisibleRegionsDirty;
-    LayerVector& currentLayers(
-            const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
+    LayerVector& currentLayers = const_cast<LayerVector&>(
+            mDrawingState.layersSortedByZ);
     visibleRegions |= lockPageFlip(currentLayers);
 
         const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -716,7 +707,6 @@
 
             mWormholeRegion = screenRegion.subtract(opaqueRegion);
             mVisibleRegionsDirty = false;
-            mHwWorkListDirty = true;
         }
 
     unlockPageFlip(currentLayers);
@@ -747,20 +737,6 @@
     }
 }
 
-void SurfaceFlinger::handleWorkList()
-{
-    mHwWorkListDirty = false;
-    HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
-    if (hwc.initCheck() == NO_ERROR) {
-        const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
-        const size_t count = currentLayers.size();
-        hwc.createWorkList(count);
-        hwc_layer_t* const cur(hwc.getLayers());
-        for (size_t i=0 ; cur && i<count ; i++) {
-            currentLayers[i]->setGeometry(&cur[i]);
-        }
-    }
-}
 
 void SurfaceFlinger::handleRepaint()
 {
@@ -825,72 +801,9 @@
         // draw something...
         drawWormhole();
     }
-
-    status_t err = NO_ERROR;
     const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
-    size_t count = layers.size();
-
-    const DisplayHardware& hw(graphicPlane(0).displayHardware());
-    HWComposer& hwc(hw.getHwComposer());
-    hwc_layer_t* const cur(hwc.getLayers());
-
-    LOGE_IF(cur && hwc.getNumLayers() != count,
-            "HAL number of layers (%d) doesn't match surfaceflinger (%d)",
-            hwc.getNumLayers(), count);
-
-    // just to be extra-safe, use the smallest count
-    if (hwc.initCheck() == NO_ERROR) {
-        count = count < hwc.getNumLayers() ? count : hwc.getNumLayers();
-    }
-
-    /*
-     *  update the per-frame h/w composer data for each layer
-     *  and build the transparent region of the FB
-     */
-    Region transparent;
-    if (cur) {
-        for (size_t i=0 ; i<count ; i++) {
-            const sp<LayerBase>& layer(layers[i]);
-            layer->setPerFrameData(&cur[i]);
-            if (cur[i].hints & HWC_HINT_CLEAR_FB) {
-                if (!(layer->needsBlending())) {
-                    transparent.orSelf(layer->visibleRegionScreen);
-                }
-            }
-        }
-        err = hwc.prepare();
-        LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
-    }
-
-    /*
-     *  clear the area of the FB that need to be transparent
-     */
-    transparent.andSelf(dirty);
-    if (!transparent.isEmpty()) {
-        glClearColor(0,0,0,0);
-        Region::const_iterator it = transparent.begin();
-        Region::const_iterator const end = transparent.end();
-        const int32_t height = hw.getHeight();
-        while (it != end) {
-            const Rect& r(*it++);
-            const GLint sy = height - (r.top + r.height());
-            glScissor(r.left, sy, r.width(), r.height());
-            glClear(GL_COLOR_BUFFER_BIT);
-        }
-    }
-
-
-    /*
-     * and then, render the layers targeted at the framebuffer
-     */
-    for (size_t i=0 ; i<count ; i++) {
-        if (cur) {
-            if (!(cur[i].compositionType == HWC_FRAMEBUFFER) ||
-                    cur[i].flags & HWC_SKIP_LAYER) {
-                // skip layers handled by the HAL
-                continue;
-            }
-        }
+    const size_t count = layers.size();
+    for (size_t i=0 ; i<count ; ++i) {
         const sp<LayerBase>& layer(layers[i]);
         const Region clip(dirty.intersect(layer->visibleRegionScreen));
         if (!clip.isEmpty()) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8e286e5..8ecfc01 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -296,7 +296,6 @@
             void        handlePageFlip();
             bool        lockPageFlip(const LayerVector& currentLayers);
             void        unlockPageFlip(const LayerVector& currentLayers);
-            void        handleWorkList();
             void        handleRepaint();
             void        postFramebuffer();
             void        composeSurfaces(const Region& dirty);
@@ -371,7 +370,6 @@
                 Region                      mInvalidRegion;
                 Region                      mWormholeRegion;
                 bool                        mVisibleRegionsDirty;
-                bool                        mHwWorkListDirty;
                 bool                        mDeferReleaseConsole;
                 bool                        mFreezeDisplay;
                 int32_t                     mFreezeCount;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 819cfbe..8e08592 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -16,16 +16,17 @@
 
 package com.android.internal.telephony;
 
+import com.android.internal.telephony.sip.SipPhone;
+
 import android.content.Context;
+import android.media.AudioManager;
 import android.os.AsyncResult;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RegistrantList;
-import android.util.Log;
-
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
-
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -52,7 +53,7 @@
  */
 public final class CallManager {
 
-    private static final String LOG_TAG ="GSM";
+    private static final String LOG_TAG ="Phone";
     private static final boolean LOCAL_DEBUG = true;
 
     private static final int EVENT_DISCONNECT = 100;
@@ -303,6 +304,32 @@
         }
     }
 
+    public void setAudioMode() {
+        Context context = getContext();
+        if (context == null) return;
+        AudioManager audioManager = (AudioManager)
+                context.getSystemService(Context.AUDIO_SERVICE);
+
+        int mode = AudioManager.MODE_NORMAL;
+        switch (getState()) {
+            case RINGING:
+                mode = AudioManager.MODE_RINGTONE;
+                break;
+            case OFFHOOK:
+                Phone fgPhone = getFgPhone();
+                if (!(fgPhone instanceof SipPhone)) {
+                    mode = AudioManager.MODE_IN_CALL;
+                }
+                break;
+        }
+        audioManager.setMode(mode);
+    }
+
+    private Context getContext() {
+        Phone defaultPhone = getDefaultPhone();
+        return ((defaultPhone == null) ? null : defaultPhone.getContext());
+    }
+
     private void registerForPhoneStates(Phone phone) {
         phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
         phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
@@ -453,7 +480,7 @@
             heldPhone = heldCall.getPhone();
         }
 
-        return (heldPhone == activePhone);
+        return heldPhone.getClass().equals(activePhone.getClass());
     }
 
     /**
@@ -466,10 +493,14 @@
      * In these cases, this operation may not be performed.
      */
     public void conference(Call heldCall) throws CallStateException {
-        if (canConference(heldCall))
+        Phone fgPhone = getFgPhone();
+        if (fgPhone instanceof SipPhone) {
+            ((SipPhone) fgPhone).conference(heldCall);
+        } else if (canConference(heldCall)) {
+            fgPhone.conference();
+        } else {
             throw(new CallStateException("Can't conference foreground and selected background call"));
-
-        heldCall.getPhone().conference();
+        }
     }
 
     /**
@@ -1288,7 +1319,10 @@
                     mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
                     break;
                 case EVENT_INCOMING_RING:
-                    mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+                    // The event may come from RIL who's not aware of an ongoing fg call
+                    if (!hasActiveFgCall()) {
+                        mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+                    }
                     break;
                 case EVENT_RINGBACK_TONE:
                     mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index a94518f..a052db0 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -21,6 +21,7 @@
 import android.content.SharedPreferences;
 import android.net.Uri;
 import android.net.rtp.AudioGroup;
+import android.net.rtp.AudioStream;
 import android.net.sip.SipAudioCall;
 import android.net.sip.SipManager;
 import android.net.sip.SipProfile;
@@ -221,7 +222,21 @@
     }
 
     public void conference() throws CallStateException {
-        // TODO
+        if ((foregroundCall.getState() != SipCall.State.ACTIVE)
+                || (foregroundCall.getState() != SipCall.State.ACTIVE)) {
+            throw new CallStateException("wrong state to merge calls: fg="
+                    + foregroundCall.getState() + ", bg="
+                    + backgroundCall.getState());
+        }
+        foregroundCall.merge(backgroundCall);
+    }
+
+    public void conference(Call that) throws CallStateException {
+        if (!(that instanceof SipCall)) {
+            throw new CallStateException("expect " + SipCall.class
+                    + ", cannot merge with " + that.getClass());
+        }
+        foregroundCall.merge((SipCall) that);
     }
 
     public boolean canTransfer() {
@@ -467,6 +482,18 @@
             return (audioGroup.getMode() == AudioGroup.MODE_MUTED);
         }
 
+        void merge(SipCall that) throws CallStateException {
+            AudioGroup myGroup = getAudioGroup();
+            for (Connection c : that.connections) {
+                SipConnection conn = (SipConnection) c;
+                conn.mergeTo(myGroup);
+                connections.add(conn);
+                conn.changeOwner(this);
+            }
+            that.connections.clear();
+            that.setState(Call.State.IDLE);
+        }
+
         void sendDtmf(char c) {
             AudioGroup audioGroup = getAudioGroup();
             if (audioGroup == null) return;
@@ -541,6 +568,7 @@
     private class SipConnection extends SipConnectionBase {
         private SipCall mOwner;
         private SipAudioCall mSipAudioCall;
+        private AudioGroup mOriginalGroup;
         private Call.State mState = Call.State.IDLE;
         private SipProfile mPeer;
         private boolean mIncoming = false;
@@ -660,6 +688,16 @@
             }
         }
 
+        void mergeTo(AudioGroup group) throws CallStateException {
+            AudioStream stream = mSipAudioCall.getAudioStream();
+            if (stream == null) {
+                throw new CallStateException("wrong state to merge: "
+                        + mSipAudioCall.getState());
+            }
+            if (mOriginalGroup == null) mOriginalGroup = getAudioGroup();
+            stream.join(group);
+        }
+
         @Override
         protected void setState(Call.State state) {
             if (state == mState) return;
@@ -694,6 +732,8 @@
 
         @Override
         public void hangup() throws CallStateException {
+            // TODO: need to pull AudioStream out of the AudioGroup in case
+            // this conn was part of a conf call
             Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
                     + ": on phone " + getPhone());
             try {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 4a22b68..9d21521 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -307,6 +307,16 @@
     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
 
     /**
+     * In this Wi-Fi lock mode, Wi-Fi will behave as in the mode
+     * {@link #WIFI_MODE_FULL} but it operates at high performance
+     * at the expense of power. This mode should be used
+     * only when the wifi connection needs to have minimum loss and low
+     * latency as it can impact the battery life.
+     * @hide
+     */
+    public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
+
+    /**
      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
      * and will behave normally, i.e., it will attempt to automatically
      * establish a connection to a remembered access point that is
@@ -993,8 +1003,9 @@
     /**
      * Creates a new WifiLock.
      *
-     * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL} and
-     * {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks.
+     * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
+     * and {@link #WIFI_MODE_SCAN_ONLY} for descriptions of the types of Wi-Fi locks.
+     *
      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is 
      *            never shown to the user under normal conditions, but should be descriptive 
      *            enough to identify your application and the specific WifiLock within it, if it
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 7a3282c..25f05c0 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -149,6 +149,8 @@
 
     public native static String getDhcpError();
 
+    public native static boolean setSuspendOptimizationsCommand(boolean enabled);
+
     /**
      * Wait for the supplicant to send an event, returning the event string.
      * @return the event string sent by the supplicant.
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index f57df62..0cc1f46 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -276,6 +276,9 @@
     
     private boolean mIsScanModeActive;
     private boolean mEnableRssiPolling;
+    private boolean mIsHighPerfEnabled;
+    private int mPowerModeRefCount = 0;
+    private int mOptimizationsDisabledRefCount = 0;
 
     /**
      * One of  {@link WifiManager#WIFI_STATE_DISABLED},
@@ -659,6 +662,67 @@
         }
     }
 
+    /**
+     * Set suspend mode optimizations. These include:
+     * - packet filtering
+     * - turn off roaming
+     * - DTIM settings
+     *
+     * Uses reference counting to keep the suspend optimizations disabled
+     * as long as one entity wants optimizations disabled.
+     *
+     * For example, WifiLock can keep suspend optimizations disabled
+     * or the user setting (wifi never sleeps) can keep suspend optimizations
+     * disabled. As long as one entity wants it disabled, it should stay
+     * that way
+     *
+     * @param enabled true if optimizations need enabled, false otherwise
+     */
+    public synchronized void setSuspendModeOptimizations(boolean enabled) {
+
+        /* It is good to plumb suspend optimization enable
+         * or disable even if ref count indicates already done
+         * since we could have a case of previous failure.
+         */
+        if (!enabled) {
+            mOptimizationsDisabledRefCount++;
+        } else {
+            mOptimizationsDisabledRefCount--;
+            if (mOptimizationsDisabledRefCount > 0) {
+                return;
+            } else {
+                /* Keep refcount from becoming negative */
+                mOptimizationsDisabledRefCount = 0;
+            }
+        }
+
+        if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
+            return;
+        }
+
+        WifiNative.setSuspendOptimizationsCommand(enabled);
+    }
+
+
+    /**
+     * Set high performance mode of operation. This would mean
+     * use active power mode and disable suspend optimizations
+     * @param enabled true if enabled, false otherwise
+     */
+    public synchronized void setHighPerfMode(boolean enabled) {
+        if (mIsHighPerfEnabled != enabled) {
+            if (enabled) {
+                setPowerMode(DRIVER_POWER_MODE_ACTIVE);
+                setSuspendModeOptimizations(false);
+            } else {
+                setPowerMode(DRIVER_POWER_MODE_AUTO);
+                setSuspendModeOptimizations(true);
+            }
+            mIsHighPerfEnabled = enabled;
+            Log.d(TAG,"high performance mode: " + enabled);
+        }
+    }
+
 
     private void checkIsBluetoothPlaying() {
         boolean isBluetoothPlaying = false;
@@ -744,6 +808,9 @@
                 dhcpThread.start();
                 mDhcpTarget = new DhcpHandler(dhcpThread.getLooper(), this);
                 mIsScanModeActive = true;
+                mIsHighPerfEnabled = false;
+                mOptimizationsDisabledRefCount = 0;
+                mPowerModeRefCount = 0;
                 mTornDownByConnMgr = false;
                 mLastBssid = null;
                 mLastSsid = null;
@@ -1947,13 +2014,41 @@
      * @param mode
      *     DRIVER_POWER_MODE_AUTO
      *     DRIVER_POWER_MODE_ACTIVE
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     *
+     * Uses reference counting to keep power mode active
+     * as long as one entity wants power mode to be active.
+     *
+     * For example, WifiLock high perf mode can keep power mode active
+     * or a DHCP session can keep it active. As long as one entity wants
+     * it enabled, it should stay that way
+     *
      */
-    public synchronized boolean setPowerMode(int mode) {
-        if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
-            return false;
+    private synchronized void setPowerMode(int mode) {
+
+        /* It is good to plumb power mode change
+         * even if ref count indicates already done
+         * since we could have a case of previous failure.
+         */
+        switch(mode) {
+            case DRIVER_POWER_MODE_ACTIVE:
+                mPowerModeRefCount++;
+                break;
+            case DRIVER_POWER_MODE_AUTO:
+                mPowerModeRefCount--;
+                if (mPowerModeRefCount > 0) {
+                    return;
+                } else {
+                    /* Keep refcount from becoming negative */
+                    mPowerModeRefCount = 0;
+                }
+                break;
         }
-        return WifiNative.setPowerModeCommand(mode);
+
+        if (mWifiState.get() != WIFI_STATE_ENABLED || isDriverStopped()) {
+            return;
+        }
+
+        WifiNative.setPowerModeCommand(mode);
     }
 
     /**