Merge "Add a unique input device descriptor."
diff --git a/Android.mk b/Android.mk
index d27dbab..9c51fc6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -118,6 +118,7 @@
 	core/java/android/net/INetworkPolicyListener.aidl \
 	core/java/android/net/INetworkPolicyManager.aidl \
 	core/java/android/net/INetworkStatsService.aidl \
+	core/java/android/net/INetworkStatsSession.aidl \
 	core/java/android/net/nsd/INsdManager.aidl \
 	core/java/android/nfc/INdefPushCallback.aidl \
 	core/java/android/nfc/INfcAdapter.aidl \
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 000abc5..a3fdf3e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -867,6 +867,16 @@
             return true;
         }
 
+        case GET_UID_FOR_INTENT_SENDER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IIntentSender r = IIntentSender.Stub.asInterface(
+                data.readStrongBinder());
+            int res = getUidForIntentSender(r);
+            reply.writeNoException();
+            reply.writeInt(res);
+            return true;
+        }
+
         case SET_PROCESS_LIMIT_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int max = data.readInt();
@@ -2714,6 +2724,18 @@
         reply.recycle();
         return res;
     }
+    public int getUidForIntentSender(IIntentSender sender) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(sender.asBinder());
+        mRemote.transact(GET_UID_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int res = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
     public void setProcessLimit(int max) throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 0f287c1..c71b186 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -175,6 +175,7 @@
     public boolean clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, int userId) throws RemoteException;
     public String getPackageForIntentSender(IIntentSender sender) throws RemoteException;
+    public int getUidForIntentSender(IIntentSender sender) throws RemoteException;
     
     public void setProcessLimit(int max) throws RemoteException;
     public int getProcessLimit() throws RemoteException;
@@ -531,6 +532,7 @@
     int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
     int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
     int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
+    int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
 
 
     int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2a9f1af..736dd24 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2034,6 +2034,38 @@
             "android.intent.action.HDMI_AUDIO_PLUG";
 
     /**
+     * Broadcast Action: A USB audio device was plugged in or unplugged.
+     *
+     * <p>The intent will have the following extra values:
+     * <ul>
+     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+     *   <li><em>card</em> - ALSA card number (integer) </li>
+     *   <li><em>device</em> - ALSA device number (integer) </li>
+     * </ul>
+     * </ul>
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
+            "android.intent.action.USB_AUDIO_DEVICE_PLUG";
+
+    /**
+     * Broadcast Action: A USB audio accessory was plugged in or unplugged.
+     *
+     * <p>The intent will have the following extra values:
+     * <ul>
+     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+     *   <li><em>card</em> - ALSA card number (integer) </li>
+     *   <li><em>device</em> - ALSA device number (integer) </li>
+     * </ul>
+     * </ul>
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_USB_AUDIO_ACCESSORY_PLUG =
+            "android.intent.action.USB_AUDIO_ACCESSORY_PLUG";
+
+    /**
      * <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p>
      * <ul>
      *   <li><em>state</em> - A boolean value indicating whether the settings is on or off.</li>
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 15ccda3..7571993 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -94,10 +94,12 @@
     public static class SplitPermissionInfo {
         public final String rootPerm;
         public final String[] newPerms;
+        public final int targetSdk;
 
-        public SplitPermissionInfo(String rootPerm, String[] newPerms) {
+        public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
             this.rootPerm = rootPerm;
             this.newPerms = newPerms;
+            this.targetSdk = targetSdk;
         }
     }
 
@@ -126,7 +128,14 @@
     public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
         new PackageParser.SplitPermissionInfo[] {
             new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
-                    new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE })
+                    new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
+                    android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
+            new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
+                    new String[] { android.Manifest.permission.READ_CALL_LOG },
+                    android.os.Build.VERSION_CODES.JELLY_BEAN),
+            new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
+                    new String[] { android.Manifest.permission.WRITE_CALL_LOG },
+                    android.os.Build.VERSION_CODES.JELLY_BEAN)
     };
 
     private String mArchiveSourcePath;
@@ -1293,8 +1302,9 @@
         for (int is=0; is<NS; is++) {
             final PackageParser.SplitPermissionInfo spi
                     = PackageParser.SPLIT_PERMISSIONS[is];
-            if (!pkg.requestedPermissions.contains(spi.rootPerm)) {
-                break;
+            if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
+                    || !pkg.requestedPermissions.contains(spi.rootPerm)) {
+                continue;
             }
             for (int in=0; in<spi.newPerms.length; in++) {
                 final String perm = spi.newPerms[in];
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 93f93c7..c40504a7 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -66,6 +66,8 @@
      * PTP function is enabled
      * <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
      * accessory function is enabled
+     * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
+     * audio source function is enabled
      * </ul>
      *
      * {@hide}
@@ -178,6 +180,14 @@
     public static final String USB_FUNCTION_PTP = "ptp";
 
     /**
+     * Name of the audio source USB function.
+     * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+     *
+     * {@hide}
+     */
+    public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
+
+    /**
      * Name of the Accessory USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 0e883cf..b4f6367 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.net.INetworkStatsSession;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
 import android.net.NetworkTemplate;
@@ -23,15 +24,11 @@
 /** {@hide} */
 interface INetworkStatsService {
 
-    /** Return historical network layer stats for traffic that matches template. */
-    NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
-    /** Return historical network layer stats for specific UID traffic that matches template. */
-    NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+    /** Start a statistics query session. */
+    INetworkStatsSession openSession();
 
-    /** Return network layer usage summary for traffic that matches template. */
-    NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
-    /** Return network layer usage summary per UID for traffic that matches template. */
-    NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+    /** Return network layer usage total for traffic that matches template. */
+    long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
 
     /** Return data layer snapshot of UID network usage. */
     NetworkStats getDataLayerSnapshotForUid(int uid);
diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl
new file mode 100644
index 0000000..1596fa2
--- /dev/null
+++ b/core/java/android/net/INetworkStatsSession.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+
+/** {@hide} */
+interface INetworkStatsSession {
+
+    /** Return network layer usage summary for traffic that matches template. */
+    NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
+    /** Return historical network layer stats for traffic that matches template. */
+    NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
+
+    /** Return network layer usage summary per UID for traffic that matches template. */
+    NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+    /** Return historical network layer stats for specific UID traffic that matches template. */
+    NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+
+    void close();
+
+}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 973fac1..ee3e165 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -238,6 +238,19 @@
         }
     }
 
+    /** {@hide} */
+    public static void closeQuietly(INetworkStatsSession session) {
+        // TODO: move to NetworkStatsService once it exists
+        if (session != null) {
+            try {
+                session.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
+            }
+        }
+    }
+
     /**
      * Get the total number of packets transmitted through the mobile interface.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 371e2a1..2aaf548 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -37,6 +37,7 @@
 import android.os.BatteryManager;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
@@ -2260,6 +2261,7 @@
 
         private static ILockSettings sLockSettings = null;
 
+        private static boolean sIsSystemProcess;
         private static final HashSet<String> MOVED_TO_LOCK_SETTINGS;
         static {
             MOVED_TO_LOCK_SETTINGS = new HashSet<String>(3);
@@ -2283,8 +2285,10 @@
             if (sLockSettings == null) {
                 sLockSettings = ILockSettings.Stub.asInterface(
                         (IBinder) ServiceManager.getService("lock_settings"));
+                sIsSystemProcess = Process.myUid() == Process.SYSTEM_UID;
             }
-            if (sLockSettings != null && MOVED_TO_LOCK_SETTINGS.contains(name)) {
+            if (sLockSettings != null && !sIsSystemProcess
+                    && MOVED_TO_LOCK_SETTINGS.contains(name)) {
                 try {
                     return sLockSettings.getString(name, "0", UserId.getCallingUserId());
                 } catch (RemoteException re) {
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index bb4b282..f7a7eb8 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -50,8 +50,6 @@
     public SpannableStringBuilder(CharSequence text, int start, int end) {
         int srclen = end - start;
 
-        if (srclen < 0) throw new StringIndexOutOfBoundsException();
-
         int len = ArrayUtils.idealCharArraySize(srclen + 1);
         mText = new char[len];
         mGapStart = srclen;
@@ -155,7 +153,7 @@
         if (where == mGapStart)
             return;
 
-        boolean atEnd = (where == length());
+        boolean atend = (where == length());
 
         if (where < mGapStart) {
             int overlap = mGapStart - where;
@@ -181,7 +179,7 @@
             else if (start == where) {
                 int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
 
-                if (flag == POINT || (atEnd && flag == PARAGRAPH))
+                if (flag == POINT || (atend && flag == PARAGRAPH))
                     start += mGapLength;
             }
 
@@ -192,7 +190,7 @@
             else if (end == where) {
                 int flag = (mSpanFlags[i] & END_MASK);
 
-                if (flag == POINT || (atEnd && flag == PARAGRAPH))
+                if (flag == POINT || (atend && flag == PARAGRAPH))
                     end += mGapLength;
             }
 
@@ -399,7 +397,7 @@
 
     // Documentation from interface
     public SpannableStringBuilder replace(final int start, final int end,
-            CharSequence tb, int tbstart, int tbend) {
+                        CharSequence tb, int tbstart, int tbend) {
         int filtercount = mFilters.length;
         for (int i = 0; i < filtercount; i++) {
             CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -421,26 +419,53 @@
         TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class);
         sendBeforeTextChanged(textWatchers, start, origLen, newLen);
 
-        // Try to keep the cursor / selection at the same relative position during
-        // a text replacement. If replaced or replacement text length is zero, this
-        // is already taken care of.
-        boolean adjustSelection = origLen != 0 && newLen != 0;
-        int selstart = 0;
-        int selend = 0;
-        if (adjustSelection) {
-            selstart = Selection.getSelectionStart(this);
-            selend = Selection.getSelectionEnd(this);
-        }
+        if (origLen == 0 || newLen == 0) {
+            change(start, end, tb, tbstart, tbend);
+        } else {
+            int selstart = Selection.getSelectionStart(this);
+            int selend = Selection.getSelectionEnd(this);
 
-        checkRange("replace", start, end);
+            // XXX just make the span fixups in change() do the right thing
+            // instead of this madness!
 
-        change(start, end, tb, tbstart, tbend);
+            checkRange("replace", start, end);
+            moveGapTo(end);
 
-        if (adjustSelection) {
+            if (mGapLength < 2)
+                resizeFor(length() + 1);
+
+            for (int i = mSpanCount - 1; i >= 0; i--) {
+                if (mSpanStarts[i] == mGapStart)
+                    mSpanStarts[i]++;
+
+                if (mSpanEnds[i] == mGapStart)
+                    mSpanEnds[i]++;
+            }
+
+            mText[mGapStart] = ' ';
+            mGapStart++;
+            mGapLength--;
+
+            if (mGapLength < 1) {
+                new Exception("mGapLength < 1").printStackTrace();
+            }
+
+            change(start + 1, start + 1, tb, tbstart, tbend);
+            change(start, start + 1, "", 0, 0);
+            change(start + newLen, start + newLen + origLen, "", 0, 0);
+
+            /*
+             * Special case to keep the cursor in the same position
+             * if it was somewhere in the middle of the replaced region.
+             * If it was at the start or the end or crossing the whole
+             * replacement, it should already be where it belongs.
+             * TODO: Is there some more general mechanism that could
+             * accomplish this?
+             */
             if (selstart > start && selstart < end) {
                 long off = selstart - start;
 
-                off = off * newLen / origLen;
+                off = off * newLen / (end - start);
                 selstart = (int) off + start;
 
                 setSpan(false, Selection.SELECTION_START, selstart, selstart,
@@ -449,7 +474,7 @@
             if (selend > start && selend < end) {
                 long off = selend - start;
 
-                off = off * newLen / origLen;
+                off = off * newLen / (end - start);
                 selend = (int) off + start;
 
                 setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d1af397..b0399fd 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -526,7 +526,7 @@
         static final int SURFACE_STATE_SUCCESS = 1;
         static final int SURFACE_STATE_UPDATED = 2;
 
-        static final int FUNCTOR_PROCESS_DELAY = 2;
+        static final int FUNCTOR_PROCESS_DELAY = 4;
 
         static EGL10 sEgl;
         static EGLDisplay sEglDisplay;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 39d2e39..2a908ab 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -260,7 +260,7 @@
             Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
             dirty.unionWith(localDirty);
 
-            if (result == DrawGlInfo::kStatusInvoke) {
+            if (result & DrawGlInfo::kStatusInvoke) {
                 mFunctors.push(f);
             }
         }
@@ -300,7 +300,7 @@
         Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
         dirty.unionWith(localDirty);
 
-        if (result == DrawGlInfo::kStatusInvoke) {
+        if (result & DrawGlInfo::kStatusInvoke) {
             mFunctors.push(functor);
         }
     }
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 66cea9d4..410383d 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -45,10 +45,16 @@
         public int mFlags;
     };
 
+    // The follow flag constants MUST stay in sync with their equivalents
+    // in MediaCodec.h !
     public static int FLAG_SYNCFRAME   = 1;
     public static int FLAG_CODECCONFIG = 2;
     public static int FLAG_EOS         = 4;
-    public static int FLAG_ENCRYPTED   = 8;
+
+    // The following mode constants MUST stay in sync with their equivalents
+    // in media/hardware/CryptoAPI.h !
+    public static int MODE_UNENCRYPTED = 0;
+    public static int MODE_AES_CTR     = 1;
 
     /** Instantiate a codec component by mime type. For decoder components
         this is the mime type of media that this decoder should be able to
@@ -176,6 +182,36 @@
             int index,
             int offset, int size, long presentationTimeUs, int flags);
 
+    /** Similar to {@link queueInputBuffer} but submits a buffer that is
+     *  potentially encrypted. The buffer's data is considered to be
+     *  partitioned into "subSamples", each subSample starts with a
+     *  (potentially empty) run of plain, unencrypted bytes followed
+     *  by a (also potentially empty) run of encrypted bytes.
+     *  @param numBytesOfClearData The number of leading unencrypted bytes in
+     *                             each subSample.
+     *  @param numBytesOfEncryptedData The number of trailing encrypted bytes
+     *                             in each subSample.
+     *  @param numSubSamples    The number of subSamples that make up the
+     *                          buffer's contents.
+     *  @param key              A 16-byte opaque key
+     *  @param iv               A 16-byte initialization vector
+     *  @param mode             The type of encryption that has been applied
+     *
+     *  Either numBytesOfClearData or numBytesOfEncryptedData (but not both)
+     *  can be null to indicate that all respective sizes are 0.
+     */
+    public native final void queueSecureInputBuffer(
+            int index,
+            int offset,
+            int[] numBytesOfClearData,
+            int[] numBytesOfEncryptedData,
+            int numSubSamples,
+            byte[] key,
+            byte[] iv,
+            int mode,
+            long presentationTimeUs,
+            int flags);
+
     // Returns the index of an input buffer to be filled with valid data
     // or -1 if no such buffer is currently available.
     // This method will return immediately if timeoutUs == 0, wait indefinitely
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 217216a..01d3833 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -126,6 +126,21 @@
     return mCodec->queueInputBuffer(index, offset, size, timeUs, flags);
 }
 
+status_t JMediaCodec::queueSecureInputBuffer(
+        size_t index,
+        size_t offset,
+        const CryptoPlugin::SubSample *subSamples,
+        size_t numSubSamples,
+        const uint8_t key[16],
+        const uint8_t iv[16],
+        CryptoPlugin::Mode mode,
+        int64_t presentationTimeUs,
+        uint32_t flags) {
+    return mCodec->queueSecureInputBuffer(
+            index, offset, subSamples, numSubSamples, key, iv, mode,
+            presentationTimeUs, flags);
+}
+
 status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
     return mCodec->dequeueInputBuffer(index, timeoutUs);
 }
@@ -367,6 +382,125 @@
     throwExceptionAsNecessary(env, err);
 }
 
+static void android_media_MediaCodec_queueSecureInputBuffer(
+        JNIEnv *env,
+        jobject thiz,
+        jint index,
+        jint offset,
+        jintArray numBytesOfClearDataObj,
+        jintArray numBytesOfEncryptedDataObj,
+        jint numSubSamples,
+        jbyteArray keyObj,
+        jbyteArray ivObj,
+        jint mode,
+        jlong timestampUs,
+        jint flags) {
+    ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+    if (codec == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    status_t err = OK;
+
+    CryptoPlugin::SubSample *subSamples = NULL;
+    jbyte *key = NULL;
+    jbyte *iv = NULL;
+
+    if (numSubSamples <= 0) {
+        err = -EINVAL;
+    } else if (numBytesOfClearDataObj == NULL
+            && numBytesOfEncryptedDataObj == NULL) {
+        err = -EINVAL;
+    } else if (numBytesOfEncryptedDataObj != NULL
+            && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) {
+        err = -ERANGE;
+    } else if (numBytesOfClearDataObj != NULL
+            && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) {
+        err = -ERANGE;
+    } else {
+        jboolean isCopy;
+
+        jint *numBytesOfClearData =
+            (numBytesOfClearDataObj == NULL)
+                ? NULL
+                : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy);
+
+        jint *numBytesOfEncryptedData =
+            (numBytesOfEncryptedDataObj == NULL)
+                ? NULL
+                : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
+
+        subSamples = new CryptoPlugin::SubSample[numSubSamples];
+
+        for (jint i = 0; i < numSubSamples; ++i) {
+            subSamples[i].mNumBytesOfClearData =
+                (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i];
+
+            subSamples[i].mNumBytesOfEncryptedData =
+                (numBytesOfEncryptedData == NULL)
+                    ? 0 : numBytesOfEncryptedData[i];
+        }
+
+        if (numBytesOfEncryptedData != NULL) {
+            env->ReleaseIntArrayElements(
+                    numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0);
+            numBytesOfEncryptedData = NULL;
+        }
+
+        if (numBytesOfClearData != NULL) {
+            env->ReleaseIntArrayElements(
+                    numBytesOfClearDataObj, numBytesOfClearData, 0);
+            numBytesOfClearData = NULL;
+        }
+    }
+
+    if (err == OK && keyObj != NULL) {
+        if (env->GetArrayLength(keyObj) != 16) {
+            err = -EINVAL;
+        } else {
+            jboolean isCopy;
+            key = env->GetByteArrayElements(keyObj, &isCopy);
+        }
+    }
+
+    if (err == OK && ivObj != NULL) {
+        if (env->GetArrayLength(ivObj) != 16) {
+            err = -EINVAL;
+        } else {
+            jboolean isCopy;
+            iv = env->GetByteArrayElements(ivObj, &isCopy);
+        }
+    }
+
+    if (err == OK) {
+        err = codec->queueSecureInputBuffer(
+                index, offset,
+                subSamples, numSubSamples,
+                (const uint8_t *)key, (const uint8_t *)iv,
+                (CryptoPlugin::Mode)mode,
+                timestampUs, flags);
+    }
+
+    if (iv != NULL) {
+        env->ReleaseByteArrayElements(ivObj, iv, 0);
+        iv = NULL;
+    }
+
+    if (key != NULL) {
+        env->ReleaseByteArrayElements(keyObj, key, 0);
+        key = NULL;
+    }
+
+    delete[] subSamples;
+    subSamples = NULL;
+
+    throwExceptionAsNecessary(env, err);
+}
+
 static jint android_media_MediaCodec_dequeueInputBuffer(
         JNIEnv *env, jobject thiz, jlong timeoutUs) {
     ALOGV("android_media_MediaCodec_dequeueInputBuffer");
@@ -532,6 +666,9 @@
     { "queueInputBuffer", "(IIIJI)V",
       (void *)android_media_MediaCodec_queueInputBuffer },
 
+    { "queueSecureInputBuffer", "(II[I[II[B[BIJI)V",
+      (void *)android_media_MediaCodec_queueSecureInputBuffer },
+
     { "dequeueInputBuffer", "(J)I",
       (void *)android_media_MediaCodec_dequeueInputBuffer },
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 6bb4071..570c33b 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -19,6 +19,7 @@
 
 #include "jni.h"
 
+#include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -53,6 +54,17 @@
             size_t index,
             size_t offset, size_t size, int64_t timeUs, uint32_t flags);
 
+    status_t queueSecureInputBuffer(
+            size_t index,
+            size_t offset,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            int64_t presentationTimeUs,
+            uint32_t flags);
+
     status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs);
 
     status_t dequeueOutputBuffer(
diff --git a/obex/MODULE_LICENSE_BSD_LIKE b/obex/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/MODULE_LICENSE_BSD_LIKE
diff --git a/obex/NOTICE b/obex/NOTICE
new file mode 100644
index 0000000..92e8e59
--- /dev/null
+++ b/obex/NOTICE
@@ -0,0 +1,29 @@
+Copyright (c) 2008-2009, Motorola, Inc.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+- Neither the name of the Motorola, Inc. nor the names of its contributors
+may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 0574405..32ac8e1 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -34,9 +34,9 @@
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.WorkSource;
 import android.text.TextUtils;
 import android.text.format.Time;
-import android.util.EventLog;
 import android.util.Slog;
 import android.util.TimeUtils;
 
@@ -50,6 +50,7 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.TimeZone;
 
@@ -89,6 +90,7 @@
     private int mDescriptor;
     private int mBroadcastRefCount = 0;
     private PowerManager.WakeLock mWakeLock;
+    private LinkedList<PendingIntent> mInFlight = new LinkedList<PendingIntent>();
     private final AlarmThread mWaitThread = new AlarmThread();
     private final AlarmHandler mHandler = new AlarmHandler();
     private ClockReceiver mClockReceiver;
@@ -668,10 +670,12 @@
                                             Intent.EXTRA_ALARM_COUNT, alarm.count),
                                     mResultReceiver, mHandler);
                             
-                            // we have an active broadcast so stay awake. 
+                            // we have an active broadcast so stay awake.
                             if (mBroadcastRefCount == 0) {
+                                setWakelockWorkSource(alarm.operation);
                                 mWakeLock.acquire();
                             }
+                            mInFlight.add(alarm.operation);
                             mBroadcastRefCount++;
                             
                             BroadcastStats bs = getStatsLocked(alarm.operation);
@@ -700,7 +704,22 @@
             }
         }
     }
-    
+
+    void setWakelockWorkSource(PendingIntent pi) {
+        try {
+            final int uid = ActivityManagerNative.getDefault()
+                    .getUidForIntentSender(pi.getTarget());
+            if (uid >= 0) {
+                mWakeLock.setWorkSource(new WorkSource(uid));
+                return;
+            }
+        } catch (Exception e) {
+        }
+
+        // Something went wrong; fall back to attributing the lock to the OS
+        mWakeLock.setWorkSource(null);
+    }
+
     private class AlarmHandler extends Handler {
         public static final int ALARM_EVENT = 1;
         public static final int MINUTE_CHANGE_EVENT = 2;
@@ -876,9 +895,20 @@
                         fs.count++;
                     }
                 }
+                mInFlight.removeFirst();
                 mBroadcastRefCount--;
                 if (mBroadcastRefCount == 0) {
                     mWakeLock.release();
+                } else {
+                    // the next of our alarms is now in flight.  reattribute the wakelock.
+                    final PendingIntent nowInFlight = mInFlight.peekFirst();
+                    if (nowInFlight != null) {
+                        setWakelockWorkSource(nowInFlight);
+                    } else {
+                        // should never happen
+                        Slog.e(TAG, "Alarm wakelock still held but sent queue empty");
+                        mWakeLock.setWorkSource(null);
+                    }
                 }
             }
         }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2da827e..80e59cd 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4444,6 +4444,17 @@
         return null;
     }
 
+    public int getUidForIntentSender(IIntentSender sender) {
+        if (sender instanceof PendingIntentRecord) {
+            try {
+                PendingIntentRecord res = (PendingIntentRecord)sender;
+                return res.uid;
+            } catch (ClassCastException e) {
+            }
+        }
+        return -1;
+    }
+
     public boolean isIntentSenderTargetedToPackage(IIntentSender pendingResult) {
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return false;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index b0657a6..77addd6 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1740,7 +1740,7 @@
 
     private long getTotalBytes(NetworkTemplate template, long start, long end) {
         try {
-            return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes();
+            return mNetworkStats.getNetworkTotalBytes(template, start, end);
         } catch (RuntimeException e) {
             Slog.w(TAG, "problem reading network stats: " + e);
             return 0;
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
index 290bd2c..540f606 100644
--- a/services/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -221,6 +221,11 @@
         if (mLastSnapshot != null) {
             mLastSnapshot = mLastSnapshot.withoutUid(uid);
         }
+
+        final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
+        if (complete != null) {
+            complete.removeUid(uid);
+        }
     }
 
     /**
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index b847673..f7ba329 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -70,6 +70,7 @@
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
 import android.net.LinkProperties;
 import android.net.NetworkIdentity;
 import android.net.NetworkInfo;
@@ -412,40 +413,75 @@
     }
 
     @Override
-    public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
-        return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+    public INetworkStatsSession openSession() {
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+
+        // return an IBinder which holds strong references to any loaded stats
+        // for its lifetime; when caller closes only weak references remain.
+
+        return new INetworkStatsSession.Stub() {
+            private NetworkStatsCollection mUidComplete;
+            private NetworkStatsCollection mUidTagComplete;
+
+            private NetworkStatsCollection getUidComplete() {
+                if (mUidComplete == null) {
+                    mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
+                }
+                return mUidComplete;
+            }
+
+            private NetworkStatsCollection getUidTagComplete() {
+                if (mUidTagComplete == null) {
+                    mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
+                }
+                return mUidTagComplete;
+            }
+
+            @Override
+            public NetworkStats getSummaryForNetwork(
+                    NetworkTemplate template, long start, long end) {
+                return mDevStatsCached.getSummary(template, start, end);
+            }
+
+            @Override
+            public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
+                return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+            }
+
+            @Override
+            public NetworkStats getSummaryForAllUid(
+                    NetworkTemplate template, long start, long end, boolean includeTags) {
+                final NetworkStats stats = getUidComplete().getSummary(template, start, end);
+                if (includeTags) {
+                    final NetworkStats tagStats = getUidTagComplete()
+                            .getSummary(template, start, end);
+                    stats.combineAllValues(tagStats);
+                }
+                return stats;
+            }
+
+            @Override
+            public NetworkStatsHistory getHistoryForUid(
+                    NetworkTemplate template, int uid, int set, int tag, int fields) {
+                if (tag == TAG_NONE) {
+                    return getUidComplete().getHistory(template, uid, set, tag, fields);
+                } else {
+                    return getUidTagComplete().getHistory(template, uid, set, tag, fields);
+                }
+            }
+
+            @Override
+            public void close() {
+                mUidComplete = null;
+                mUidTagComplete = null;
+            }
+        };
     }
 
     @Override
-    public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
-        return mDevStatsCached.getSummary(template, start, end);
-    }
-
-    @Override
-    public NetworkStatsHistory getHistoryForUid(
-            NetworkTemplate template, int uid, int set, int tag, int fields) {
-        // TODO: transition to stats sessions to avoid WeakReferences
-        if (tag == TAG_NONE) {
-            return mUidRecorder.getOrLoadCompleteLocked().getHistory(
-                    template, uid, set, tag, fields);
-        } else {
-            return mUidTagRecorder.getOrLoadCompleteLocked().getHistory(
-                    template, uid, set, tag, fields);
-        }
-    }
-
-    @Override
-    public NetworkStats getSummaryForAllUid(
-            NetworkTemplate template, long start, long end, boolean includeTags) {
-        // TODO: transition to stats sessions to avoid WeakReferences
-        final NetworkStats stats = mUidRecorder.getOrLoadCompleteLocked().getSummary(
-                template, start, end);
-        if (includeTags) {
-            final NetworkStats tagStats = mUidTagRecorder.getOrLoadCompleteLocked().getSummary(
-                    template, start, end);
-            stats.combineAllValues(tagStats);
-        }
-        return stats;
+    public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+        return mDevStatsCached.getSummary(template, start, end).getTotalBytes();
     }
 
     @Override
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 4bea5e4..1bd15f6 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -60,6 +60,7 @@
 import java.util.List;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Scanner;
 
 /**
  * UsbDeviceManager manages USB state in device mode.
@@ -81,6 +82,8 @@
             "/sys/class/android_usb/android0/f_mass_storage/lun/file";
     private static final String RNDIS_ETH_ADDR_PATH =
             "/sys/class/android_usb/android0/f_rndis/ethaddr";
+    private static final String AUDIO_SOURCE_PCM_PATH =
+            "/sys/class/android_usb/android0/f_audio_source/pcm";
 
     private static final int MSG_UPDATE_STATE = 0;
     private static final int MSG_ENABLE_ADB = 1;
@@ -105,6 +108,7 @@
     private final boolean mHasUsbAccessory;
     private boolean mUseUsbNotification;
     private boolean mAdbEnabled;
+    private boolean mAudioSourceEnabled;
     private Map<String, List<Pair<String, String>>> mOemModeMap;
 
     private class AdbSettingsObserver extends ContentObserver {
@@ -291,6 +295,8 @@
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                 updateState(state);
                 mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
+                mAudioSourceEnabled = containsFunction(mCurrentFunctions,
+                        UsbManager.USB_FUNCTION_AUDIO_SOURCE);
 
                 // Upgrade step for previous versions that used persist.service.adb.enable
                 String value = SystemProperties.get("persist.service.adb.enable", "");
@@ -504,6 +510,28 @@
             mContext.sendStickyBroadcast(intent);
         }
 
+        private void updateAudioSourceFunction(boolean enabled) {
+            // send a sticky broadcast containing current USB state
+            Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            intent.putExtra("state", (enabled ? 1 : 0));
+            if (enabled) {
+                try {
+                    Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
+                    int card = scanner.nextInt();
+                    int device = scanner.nextInt();
+                    intent.putExtra("card", card);
+                    intent.putExtra("device", device);
+                } catch (FileNotFoundException e) {
+                    Slog.e(TAG, "could not open audio source PCM file", e);
+                }
+            }
+
+            mContext.sendStickyBroadcast(intent);
+            mAudioSourceEnabled = enabled;
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -523,6 +551,11 @@
                     }
                     if (mBootCompleted) {
                         updateUsbState();
+                        boolean audioSourceEnabled = containsFunction(mCurrentFunctions,
+                                UsbManager.USB_FUNCTION_AUDIO_SOURCE);
+                        if (audioSourceEnabled != mAudioSourceEnabled) {
+                            updateAudioSourceFunction(audioSourceEnabled);
+                        }
                     }
                     break;
                 case MSG_ENABLE_ADB:
@@ -543,6 +576,7 @@
                     if (mCurrentAccessory != null) {
                         mSettingsManager.accessoryAttached(mCurrentAccessory);
                     }
+                    updateAudioSourceFunction(mAudioSourceEnabled);
                     break;
             }
         }
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 6ba4c35..003dc17 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -259,6 +259,19 @@
         return false;
     }
 
+    boolean showAllWindowsLocked() {
+        boolean isAnimating = false;
+        final int NW = mAppToken.allAppWindows.size();
+        for (int i=0; i<NW; i++) {
+            WindowStateAnimator winAnimator = mAppToken.allAppWindows.get(i).mWinAnimator;
+            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
+                    "performing show on: " + winAnimator);
+            winAnimator.performShowLocked();
+            isAnimating |= winAnimator.isAnimating();
+        }
+        return isAnimating;
+    }
+
     void dump(PrintWriter pw, String prefix) {
         if (freezingScreen) {
             pw.print(prefix); pw.print(" freezingScreen="); pw.println(freezingScreen);
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 1f8348d..bf35154 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -124,19 +124,6 @@
         }
     }
 
-    boolean showAllWindowsLocked() {
-        boolean isAnimating = false;
-        final int NW = allAppWindows.size();
-        for (int i=0; i<NW; i++) {
-            WindowStateAnimator winAnimator = allAppWindows.get(i).mWinAnimator;
-            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
-                    "performing show on: " + winAnimator);
-            winAnimator.performShowLocked();
-            isAnimating |= winAnimator.isAnimating();
-        }
-        return isAnimating;
-    }
-
     void updateReportedVisibilityLocked() {
         if (appToken == null) {
             return;
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 405dd04..b08c864 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -41,14 +41,14 @@
 
     DimAnimator (SurfaceSession session) {
         if (mDimSurface == null) {
-            if (WindowManagerService.SHOW_TRANSACTIONS ||
-                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                            "  DIM " + mDimSurface + ": CREATE");
             try {
                 mDimSurface = new Surface(session, 0,
                         "DimAnimator",
                         -1, 16, 16, PixelFormat.OPAQUE,
                         Surface.FX_SURFACE_DIM);
+                if (WindowManagerService.SHOW_TRANSACTIONS ||
+                        WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                                "  DIM " + mDimSurface + ": CREATE");
                 mDimSurface.setAlpha(0.0f);
             } catch (Exception e) {
                 Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index dc6cc0d..c1dbb36 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -32,14 +32,14 @@
 
     DimSurface(SurfaceSession session) {
         if (mDimSurface == null) {
-            if (WindowManagerService.SHOW_TRANSACTIONS ||
-                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                            "  DIM " + mDimSurface + ": CREATE");
             try {
                 mDimSurface = new Surface(session, 0,
                         "DimSurface",
                         -1, 16, 16, PixelFormat.OPAQUE,
                         Surface.FX_SURFACE_DIM);
+                if (WindowManagerService.SHOW_TRANSACTIONS ||
+                        WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                                "  DIM " + mDimSurface + ": CREATE");
                 mDimSurface.setAlpha(0.0f);
             } catch (Exception e) {
                 Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 67e057e..0d64b68 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -22,6 +22,7 @@
 import com.android.internal.policy.impl.PhoneWindowManager;
 
 import java.io.PrintWriter;
+import java.util.HashSet;
 
 /**
  * Singleton class that carries out the animations and Surface operations in a separate task
@@ -34,6 +35,9 @@
     final Context mContext;
     final WindowManagerPolicy mPolicy;
 
+    HashSet<WindowStateAnimator> mWinAnimators = new HashSet<WindowStateAnimator>();
+    HashSet<WindowStateAnimator> mFinished = new HashSet<WindowStateAnimator>();
+
     boolean mAnimating;
     boolean mTokenMayBeDrawn;
     boolean mForceHiding;
@@ -171,16 +175,16 @@
         ++mTransactionSequence;
 
         for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
-            WindowState w = mService.mWindows.get(i);
-            WindowStateAnimator winAnimator = w.mWinAnimator;
-            final WindowManager.LayoutParams attrs = w.mAttrs;
+            WindowState win = mService.mWindows.get(i);
+            WindowStateAnimator winAnimator = win.mWinAnimator;
+            final int flags = winAnimator.mAttrFlags;
 
             if (winAnimator.mSurface != null) {
                 final boolean wasAnimating = winAnimator.mWasAnimating;
                 final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
 
                 if (WindowManagerService.DEBUG_WALLPAPER) {
-                    Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
+                    Slog.v(TAG, win + ": wasAnimating=" + wasAnimating +
                             ", nowAnimating=" + nowAnimating);
                 }
 
@@ -189,16 +193,16 @@
                 // a detached wallpaper animation.
                 if (nowAnimating) {
                     if (winAnimator.mAnimation != null) {
-                        if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                        if ((flags & FLAG_SHOW_WALLPAPER) != 0
                                 && winAnimator.mAnimation.getDetachWallpaper()) {
-                            mDetachedWallpaper = w;
+                            mDetachedWallpaper = win;
                         }
                         final int backgroundColor = winAnimator.mAnimation.getBackgroundColor();
                         if (backgroundColor != 0) {
                             if (mWindowAnimationBackground == null
                                     || (winAnimator.mAnimLayer <
                                             mWindowAnimationBackground.mWinAnimator.mAnimLayer)) {
-                                mWindowAnimationBackground = w;
+                                mWindowAnimationBackground = win;
                                 mWindowAnimationBackgroundColor = backgroundColor;
                             }
                         }
@@ -210,25 +214,25 @@
                 // animation, make a note so we can ensure the wallpaper is
                 // displayed behind it.
                 final AppWindowAnimator appAnimator =
-                        w.mAppToken == null ? null : w.mAppToken.mAppAnimator;
+                        win.mAppToken == null ? null : win.mAppToken.mAppAnimator;
                 if (appAnimator != null && appAnimator.animation != null
                         && appAnimator.animating) {
-                    if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                    if ((flags & FLAG_SHOW_WALLPAPER) != 0
                             && appAnimator.animation.getDetachWallpaper()) {
-                        mDetachedWallpaper = w;
+                        mDetachedWallpaper = win;
                     }
                     final int backgroundColor = appAnimator.animation.getBackgroundColor();
                     if (backgroundColor != 0) {
                         if (mWindowAnimationBackground == null
                                 || (winAnimator.mAnimLayer <
                                         mWindowAnimationBackground.mWinAnimator.mAnimLayer)) {
-                            mWindowAnimationBackground = w;
+                            mWindowAnimationBackground = win;
                             mWindowAnimationBackgroundColor = backgroundColor;
                         }
                     }
                 }
 
-                if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == w) {
+                if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {
                     mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
                     mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -237,11 +241,11 @@
                     }
                 }
 
-                if (mPolicy.doesForceHide(w, attrs)) {
+                if (mPolicy.doesForceHide(win, win.mAttrs)) {
                     if (!wasAnimating && nowAnimating) {
                         if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                                 "Animation started that could impact force hide: "
-                                + w);
+                                + win);
                         mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
                         mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -249,22 +253,22 @@
                                 mPendingLayoutChanges);
                         }
                         mService.mFocusMayChange = true;
-                    } else if (w.isReadyForDisplay() && winAnimator.mAnimation == null) {
+                    } else if (win.isReadyForDisplay() && winAnimator.mAnimation == null) {
                         mForceHiding = true;
                     }
-                } else if (mPolicy.canBeForceHidden(w, attrs)) {
+                } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
                     final boolean changed;
                     if (mForceHiding) {
-                        changed = w.hideLw(false, false);
+                        changed = win.hideLw(false, false);
                         if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy hidden: " + w);
+                                "Now policy hidden: " + win);
                     } else {
-                        changed = w.showLw(false, false);
+                        changed = win.showLw(false, false);
                         if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy shown: " + w);
+                                "Now policy shown: " + win);
                         if (changed) {
                             if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
-                                    && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
+                                    && win.isVisibleNow() /*w.isReadyForDisplay()*/) {
                                 // Assume we will need to animate.  If
                                 // we don't (because the wallpaper will
                                 // stay with the lock screen), then we will
@@ -274,7 +278,7 @@
                                     winAnimator.setAnimation(a);
                                 }
                             }
-                            if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) {
+                            if (mCurrentFocus == null || mCurrentFocus.mLayer < win.mLayer) {
                                 // We are showing on to of the current
                                 // focus, so re-evaluate focus to make
                                 // sure it is correct.
@@ -282,8 +286,7 @@
                             }
                         }
                     }
-                    if (changed && (attrs.flags
-                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                    if (changed && (flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
                         mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
                         mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -294,44 +297,43 @@
                 }
             }
 
-            final AppWindowToken atoken = w.mAppToken;
+            final AppWindowToken atoken = win.mAppToken;
             if (atoken != null && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
                 if (atoken.lastTransactionSequence != mTransactionSequence) {
                     atoken.lastTransactionSequence = mTransactionSequence;
                     atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
                     atoken.startingDisplayed = false;
                 }
-                if ((w.isOnScreen() || w.mAttrs.type
+                if ((win.isOnScreen() || winAnimator.mAttrType
                         == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
-                        && !w.mExiting && !w.mDestroying) {
+                        && !win.mExiting && !win.mDestroying) {
                     if (WindowManagerService.DEBUG_VISIBILITY ||
                             WindowManagerService.DEBUG_ORIENTATION) {
-                        Slog.v(TAG, "Eval win " + w + ": isDrawn="
-                                + w.isDrawnLw()
+                        Slog.v(TAG, "Eval win " + win + ": isDrawn=" + win.isDrawnLw()
                                 + ", isAnimating=" + winAnimator.isAnimating());
-                        if (!w.isDrawnLw()) {
+                        if (!win.isDrawnLw()) {
                             Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
-                                    + " pv=" + w.mPolicyVisibility
+                                    + " pv=" + win.mPolicyVisibility
                                     + " mDrawState=" + winAnimator.mDrawState
-                                    + " ah=" + w.mAttachedHidden
+                                    + " ah=" + win.mAttachedHidden
                                     + " th=" + atoken.hiddenRequested
                                     + " a=" + winAnimator.mAnimating);
                         }
                     }
-                    if (w != atoken.startingWindow) {
-                        if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
+                    if (win != atoken.startingWindow) {
+                        if (!atoken.mAppAnimator.freezingScreen || !win.mAppFreezing) {
                             atoken.numInterestingWindows++;
-                            if (w.isDrawnLw()) {
+                            if (win.isDrawnLw()) {
                                 atoken.numDrawnWindows++;
                                 if (WindowManagerService.DEBUG_VISIBILITY ||
                                         WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
                                         "tokenMayBeDrawn: " + atoken
                                         + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
-                                        + " mAppFreezing=" + w.mAppFreezing);
+                                        + " mAppFreezing=" + win.mAppFreezing);
                                 mTokenMayBeDrawn = true;
                             }
                         }
-                    } else if (w.isDrawnLw()) {
+                    } else if (win.isDrawnLw()) {
                         atoken.startingDisplayed = true;
                     }
                 }
@@ -371,7 +373,7 @@
                             "allDrawn: " + wtoken
                             + " interesting=" + numInteresting
                             + " drawn=" + wtoken.numDrawnWindows);
-                    wtoken.showAllWindowsLocked();
+                    wtoken.mAppAnimator.showAllWindowsLocked();
                     mService.unsetAppFreezingScreenLocked(wtoken, false, true);
                     if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
                             "Setting mOrientationChangeComplete=true because wtoken "
@@ -394,7 +396,7 @@
 
                     // We can now show all of the drawn windows!
                     if (!mService.mOpeningApps.contains(wtoken)) {
-                        mAnimating |= wtoken.showAllWindowsLocked();
+                        mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
                     }
                 }
             }
@@ -435,9 +437,16 @@
                 mScreenRotationAnimation.updateSurfaces();
             }
 
-            for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
-                WindowState w = mService.mWindows.get(i);
-                w.mWinAnimator.prepareSurfaceLocked(true);
+            mFinished.clear();
+            for (final WindowStateAnimator winAnimator : mWinAnimators) {
+                if (winAnimator.mSurface == null) {
+                    mFinished.add(winAnimator);
+                } else {
+                    winAnimator.prepareSurfaceLocked(true);
+                }
+            }
+            for (final WindowStateAnimator winAnimator : mFinished) {
+                mWinAnimators.remove(winAnimator);
             }
 
             if (mDimParams != null) {
@@ -509,4 +518,18 @@
             pw.println( "  no DimAnimator ");
         }
     }
+
+    static class SetAnimationParams {
+        final WindowStateAnimator mWinAnimator;
+        final Animation mAnimation;
+        final int mAnimDw;
+        final int mAnimDh;
+        public SetAnimationParams(final WindowStateAnimator winAnimator,
+                                  final Animation animation, final int animDw, final int animDh) {
+            mWinAnimator = winAnimator;
+            mAnimation = animation;
+            mAnimDw = animDw;
+            mAnimDh = animDh;
+        }
+    }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 716b7b1..6f7852d 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -351,32 +351,7 @@
      * controlling the ordering of windows in different applications.  This
      * contains AppWindowToken objects.
      */
-    final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>() {
-        @Override
-        public void add(int index, AppWindowToken object) {
-            synchronized (mAnimator) {
-                super.add(index, object);
-            }
-        };
-        @Override
-        public boolean add(AppWindowToken object) {
-            synchronized (mAnimator) {
-                return super.add(object);
-            }
-        };
-        @Override
-        public AppWindowToken remove(int index) {
-            synchronized (mAnimator) {
-                return super.remove(index);
-            }
-        };
-        @Override
-        public boolean remove(Object object) {
-            synchronized (mAnimator) {
-                return super.remove(object);
-            }
-        };
-    };
+    final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
 
     /**
      * Application tokens that are in the process of exiting, but still
@@ -393,32 +368,7 @@
     /**
      * Z-ordered (bottom-most first) list of all Window objects.
      */
-    final ArrayList<WindowState> mWindows = new ArrayList<WindowState>() {
-        @Override
-        public void add(int index, WindowState object) {
-            synchronized (mAnimator) {
-                super.add(index, object);
-            }
-        };
-        @Override
-        public boolean add(WindowState object) {
-            synchronized (mAnimator) {
-                return super.add(object);
-            }
-        };
-        @Override
-        public WindowState remove(int index) {
-            synchronized (mAnimator) {
-                return super.remove(index);
-            }
-        };
-        @Override
-        public boolean remove(Object object) {
-            synchronized (mAnimator) {
-                return super.remove(object);
-            }
-        };
-    };
+    final ArrayList<WindowState> mWindows = new ArrayList<WindowState>();
 
     /**
      * Fake windows added to the window manager.  Note: ordered from top to
@@ -6504,6 +6454,7 @@
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
         public static final int SET_WALLPAPER_OFFSET = ANIMATOR_WHAT_OFFSET + 2;
         public static final int SET_DIM_PARAMETERS = ANIMATOR_WHAT_OFFSET + 3;
+        public static final int SET_MOVE_ANIMATION = ANIMATOR_WHAT_OFFSET + 4;
 
         private Session mLastReportedHold;
 
@@ -6942,33 +6893,37 @@
 
                 // Animation messages. Move to Window{State}Animator
                 case SET_TRANSPARENT_REGION: {
-                    // TODO(cmautner): Remove sync.
-                    synchronized (mAnimator) {
-                        Pair<WindowStateAnimator, Region> pair =
+                    Pair<WindowStateAnimator, Region> pair =
                                 (Pair<WindowStateAnimator, Region>) msg.obj;
-                        final WindowStateAnimator winAnimator = pair.first;
-                        winAnimator.setTransparentRegionHint(pair.second);
-                    }
+                    final WindowStateAnimator winAnimator = pair.first;
+                    winAnimator.setTransparentRegionHint(pair.second);
 
                     scheduleAnimationLocked();
                     break;
                 }
 
                 case SET_WALLPAPER_OFFSET: {
-                    // TODO(cmautner): Remove sync.
-                    synchronized (mAnimator) {
-                        final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
-                        winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
-                    }
+                    final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
+                    winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
 
                     scheduleAnimationLocked();
                     break;
                 }
 
                 case SET_DIM_PARAMETERS: {
-                    synchronized (mAnimator) {
-                        mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
-                    }
+                    mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
+
+                    scheduleAnimationLocked();
+                    break;
+                }
+
+                case SET_MOVE_ANIMATION: {
+                    WindowAnimator.SetAnimationParams params =
+                            (WindowAnimator.SetAnimationParams) msg.obj;
+                    WindowStateAnimator winAnimator = params.mWinAnimator;
+                    winAnimator.setAnimation(params.mAnimation);
+                    winAnimator.mAnimDw = params.mAnimDw;
+                    winAnimator.mAnimDh = params.mAnimDh;
 
                     scheduleAnimationLocked();
                     break;
@@ -7752,20 +7707,19 @@
             AppWindowToken topOpeningApp = null;
             int topOpeningLayer = 0;
 
+            // TODO(cmautner): Move to animation side.
             NN = mOpeningApps.size();
             for (i=0; i<NN; i++) {
                 AppWindowToken wtoken = mOpeningApps.get(i);
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                        "Now opening app" + wtoken);
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
                 wtoken.mAppAnimator.clearThumbnail();
                 wtoken.reportedVisible = false;
                 wtoken.inPendingTransaction = false;
                 wtoken.mAppAnimator.animation = null;
-                setTokenVisibilityLocked(wtoken, animLp, true,
-                        transit, false);
+                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToShow = false;
-                mAnimator.mAnimating |= wtoken.showAllWindowsLocked();
+                mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
                 if (animLp != null) {
                     int layer = -1;
                     for (int j=0; j<wtoken.windows.size(); j++) {
@@ -8624,6 +8578,7 @@
                         wsa.mSurfaceShown = false;
                         wsa.mSurface = null;
                         ws.mHasSurface = false;
+                        mAnimator.mWinAnimators.remove(wsa);
                         mForceRemoves.add(ws);
                         i--;
                         N--;
@@ -8637,6 +8592,7 @@
                         wsa.mSurfaceShown = false;
                         wsa.mSurface = null;
                         ws.mHasSurface = false;
+                        mAnimator.mWinAnimators.remove(wsa);
                         leakedSurface = true;
                     }
                 }
@@ -8676,6 +8632,7 @@
                     winAnimator.mSurfaceShown = false;
                     winAnimator.mSurface = null;
                     winAnimator.mWin.mHasSurface = false;
+                    mAnimator.mWinAnimators.remove(winAnimator);
                 }
 
                 try {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 6d0921e..220f5e0 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -121,6 +121,9 @@
     /** Was this window last hidden? */
     boolean mLastHidden;
 
+    int mAttrFlags;
+    int mAttrType;
+
     public WindowStateAnimator(final WindowManagerService service, final WindowState win,
                                final WindowState attachedWindow) {
         mService = service;
@@ -130,11 +133,12 @@
         mSession = win.mSession;
         mPolicy = mService.mPolicy;
         mContext = mService.mContext;
+        mAttrFlags = win.mAttrs.flags;
+        mAttrType = win.mAttrs.type;
     }
 
     public void setAnimation(Animation anim) {
-        if (localLOGV) Slog.v(
-            TAG, "Setting animation in " + this + ": " + anim);
+        if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
         mAnimating = false;
         mLocalAnimating = false;
         mAnimation = anim;
@@ -453,6 +457,7 @@
                         attrs.getTitle().toString(),
                         0, w, h, format, flags);
                 mWin.mHasSurface = true;
+                mAnimator.mWinAnimators.add(this);
                 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
                         "  CREATE SURFACE "
                         + mSurface + " IN SESSION "
@@ -463,12 +468,14 @@
                         + " / " + this);
             } catch (Surface.OutOfResourcesException e) {
                 mWin.mHasSurface = false;
+                mAnimator.mWinAnimators.remove(this);
                 Slog.w(TAG, "OutOfResourcesException creating surface");
                 mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
                 mDrawState = NO_SURFACE;
                 return null;
             } catch (Exception e) {
                 mWin.mHasSurface = false;
+                mAnimator.mWinAnimators.remove(this);
                 Slog.e(TAG, "Exception creating surface", e);
                 mDrawState = NO_SURFACE;
                 return null;
@@ -586,6 +593,7 @@
             mSurfaceShown = false;
             mSurface = null;
             mWin.mHasSurface =false;
+            mAnimator.mWinAnimators.remove(this);
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 1773e33..2033db6 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -70,7 +70,6 @@
 import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.MessageQueue.IdleHandler;
-import android.os.SystemClock;
 import android.os.UserId;
 import android.test.AndroidTestCase;
 import android.test.mock.MockPackageManager;
@@ -628,8 +627,8 @@
         // pretend that 512 bytes total have happened
         stats = new NetworkStats(getElapsedRealtime(), 1)
                 .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L);
-        expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
-                .andReturn(stats).atLeastOnce();
+        expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
+                .andReturn(stats.getTotalBytes()).atLeastOnce();
         expectPolicyDataEnable(TYPE_WIFI, true);
 
         // TODO: consider making strongly ordered mock
@@ -699,8 +698,8 @@
         {
             expectCurrentTime();
             expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
-            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
-                    .andReturn(stats).atLeastOnce();
+            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+                    .andReturn(stats.getTotalBytes()).atLeastOnce();
             expectPolicyDataEnable(TYPE_WIFI, true);
 
             expectClearNotifications();
@@ -722,8 +721,8 @@
         {
             expectCurrentTime();
             expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
-            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
-                    .andReturn(stats).atLeastOnce();
+            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+                    .andReturn(stats.getTotalBytes()).atLeastOnce();
             expectPolicyDataEnable(TYPE_WIFI, true);
 
             expectRemoveInterfaceQuota(TEST_IFACE);
@@ -745,8 +744,8 @@
 
         {
             expectCurrentTime();
-            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
-                    .andReturn(stats).atLeastOnce();
+            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+                    .andReturn(stats.getTotalBytes()).atLeastOnce();
             expectPolicyDataEnable(TYPE_WIFI, true);
 
             expectForceUpdate();
@@ -766,8 +765,8 @@
 
         {
             expectCurrentTime();
-            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
-                    .andReturn(stats).atLeastOnce();
+            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+                    .andReturn(stats.getTotalBytes()).atLeastOnce();
             expectPolicyDataEnable(TYPE_WIFI, false);
 
             expectForceUpdate();
@@ -786,8 +785,8 @@
         {
             expectCurrentTime();
             expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
-            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
-                    .andReturn(stats).atLeastOnce();
+            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+                    .andReturn(stats.getTotalBytes()).atLeastOnce();
             expectPolicyDataEnable(TYPE_WIFI, true);
 
             // snoozed interface still has high quota so background data is
@@ -827,8 +826,8 @@
         {
             expectCurrentTime();
             expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
-            expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
-                    .andReturn(stats).atLeastOnce();
+            expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis()))
+                    .andReturn(stats.getTotalBytes()).atLeastOnce();
             expectPolicyDataEnable(TYPE_WIFI, true);
 
             expectRemoveInterfaceQuota(TEST_IFACE);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 103d8e1..6d9bb29 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -54,6 +54,7 @@
 import android.content.Intent;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
+import android.net.INetworkStatsSession;
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
@@ -84,7 +85,7 @@
  */
 @LargeTest
 public class NetworkStatsServiceTest extends AndroidTestCase {
-    private static final String TAG  = "NetworkStatsServiceTest";
+    private static final String TAG = "NetworkStatsServiceTest";
 
     private static final String TEST_IFACE = "test0";
     private static final String TEST_IFACE2 = "test1";
@@ -113,6 +114,7 @@
     private IConnectivityManager mConnManager;
 
     private NetworkStatsService mService;
+    private INetworkStatsSession mSession;
     private INetworkManagementEventObserver mNetworkObserver;
 
     @Override
@@ -134,6 +136,7 @@
         mService = new NetworkStatsService(
                 mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings);
         mService.bindConnectivityManager(mConnManager);
+        mSession = mService.openSession();
 
         mElapsedRealtime = 0L;
 
@@ -172,6 +175,7 @@
         mSettings = null;
         mConnManager = null;
 
+        mSession.close();
         mService = null;
 
         super.tearDown();
@@ -349,7 +353,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify service recorded history
-        history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
+        history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
         assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
         assertEquals(2, history.size());
@@ -367,7 +371,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // verify identical stats, but spread across 4 buckets now
-        history = mService.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
+        history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
         assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
         assertEquals(4, history.size());
@@ -652,7 +656,7 @@
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
 
         // first verify entire history present
-        NetworkStats stats = mService.getSummaryForAllUid(
+        NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(3, stats.size());
         assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 1);
@@ -661,7 +665,7 @@
 
         // now verify that recent history only contains one uid
         final long currentTime = currentTimeMillis();
-        stats = mService.getSummaryForAllUid(
+        stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
         assertEquals(1, stats.size());
         assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0);
@@ -723,7 +727,7 @@
         assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2);
 
         // verify entire history present
-        final NetworkStats stats = mService.getSummaryForAllUid(
+        final NetworkStats stats = mSession.getSummaryForAllUid(
                 sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
         assertEquals(4, stats.size());
         assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 1);
@@ -775,20 +779,20 @@
     }
 
     private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
-            long txBytes, long txPackets, int operations) {
-        final NetworkStatsHistory history = mService.getHistoryForNetwork(template, FIELD_ALL);
+            long txBytes, long txPackets, int operations) throws Exception {
+        final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
                 txPackets, operations);
     }
 
     private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
-            long txBytes, long txPackets, int operations) {
+            long txBytes, long txPackets, int operations) throws Exception {
         assertUidTotal(template, uid, SET_ALL, rxBytes, rxPackets, txBytes, txPackets, operations);
     }
 
     private void assertUidTotal(NetworkTemplate template, int uid, int set, long rxBytes,
-            long rxPackets, long txBytes, long txPackets, int operations) {
-        final NetworkStatsHistory history = mService.getHistoryForUid(
+            long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
+        final NetworkStatsHistory history = mSession.getHistoryForUid(
                 template, uid, set, TAG_NONE, FIELD_ALL);
         assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
                 txPackets, operations);
diff --git a/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
index b7e80d4..919e2b3 100644
--- a/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
+++ b/tests/DataIdleTest/src/com/android/tests/dataidle/DataIdleTest.java
@@ -17,15 +17,16 @@
 
 import android.content.Context;
 import android.net.INetworkStatsService;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStats;
 import android.net.NetworkStats.Entry;
 import android.net.NetworkTemplate;
-import android.net.NetworkStats;
+import android.net.TrafficStats;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.TelephonyManager;
 import android.test.InstrumentationTestCase;
-import android.test.InstrumentationTestRunner;
 import android.util.Log;
 
 /**
@@ -71,13 +72,17 @@
      * @param template {link {@link NetworkTemplate} to match.
      */
     private void fetchStats(NetworkTemplate template) {
+        INetworkStatsSession session = null;
         try {
             mStatsService.forceUpdate();
-            NetworkStats stats = mStatsService.getSummaryForAllUid(template, Long.MIN_VALUE,
-                    Long.MAX_VALUE, false);
+            session = mStatsService.openSession();
+            final NetworkStats stats = session.getSummaryForAllUid(
+                    template, Long.MIN_VALUE, Long.MAX_VALUE, false);
             reportStats(stats);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "Failed to fetch network stats.");
+        } finally {
+            TrafficStats.closeQuietly(session);
         }
     }
 
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 198fce4..689aa8e 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -639,6 +639,12 @@
             // If an app requests write storage, they will also get read storage.
             bool hasReadExternalStoragePermission = false;
 
+            // Implement transition to read and write call log.
+            bool hasReadContactsPermission = false;
+            bool hasWriteContactsPermission = false;
+            bool hasReadCallLogPermission = false;
+            bool hasWriteCallLogPermission = false;
+
             // This next group of variables is used to implement a group of
             // backward-compatibility heuristics necessitated by the addition of
             // some new uses-feature constants in 2.1 and 2.2. In most cases, the
@@ -1006,6 +1012,14 @@
                                 hasReadExternalStoragePermission = true;
                             } else if (name == "android.permission.READ_PHONE_STATE") {
                                 hasReadPhoneStatePermission = true;
+                            } else if (name == "android.permission.READ_CONTACTS") {
+                                hasReadContactsPermission = true;
+                            } else if (name == "android.permission.WRITE_CONTACTS") {
+                                hasWriteContactsPermission = true;
+                            } else if (name == "android.permission.READ_CALL_LOG") {
+                                hasReadCallLogPermission = true;
+                            } else if (name == "android.permission.WRITE_CALL_LOG") {
+                                hasWriteCallLogPermission = true;
                             }
                             printf("uses-permission:'%s'\n", name.string());
                         } else {
@@ -1181,6 +1195,16 @@
                 printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
             }
 
+            // Pre-JellyBean call log permission compatibility.
+            if (targetSdk < 16) {
+                if (!hasReadCallLogPermission && hasReadContactsPermission) {
+                    printf("uses-permission:'android.permission.READ_CALL_LOG'\n");
+                }
+                if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
+                    printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n");
+                }
+            }
+
             /* The following blocks handle printing "inferred" uses-features, based
              * on whether related features or permissions are used by the app.
              * Note that the various spec*Feature variables denote whether the