Merge "Issue 4345021: Audio routed to multiple devices..."
diff --git a/api/current.txt b/api/current.txt
index 804a524..c3f339f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23017,6 +23017,7 @@
     method public void scrollTo(int, int);
     method public void sendAccessibilityEvent(int);
     method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
+    method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
     method public void setActivated(boolean);
     method public void setAlpha(float);
     method public void setAnimation(android.view.animation.Animation);
@@ -23193,6 +23194,17 @@
     field public static android.util.Property Y;
   }
 
+  public static class View.AccessibilityDelegate {
+    ctor public View.AccessibilityDelegate();
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo);
+    method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public void sendAccessibilityEvent(android.view.View, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+  }
+
   public static class View.BaseSavedState extends android.view.AbsSavedState {
     ctor public View.BaseSavedState(android.os.Parcel);
     ctor public View.BaseSavedState(android.os.Parcelable);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 029d107..be9070d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -189,6 +189,7 @@
     public static final String KEY_ERROR_CODE = "errorCode";
     public static final String KEY_ERROR_MESSAGE = "errorMessage";
     public static final String KEY_USERDATA = "userdata";
+
     /**
      * Authenticators using 'customTokens' option will also get the UID of the
      * caller
@@ -814,11 +815,13 @@
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        final Bundle optionsIn = options == null ? new Bundle() : options;
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.getAuthToken(mResponse, account, authTokenType,
                         false /* notifyOnAuthFailure */, true /* expectActivityLaunch */,
-                        options);
+                        optionsIn);
             }
         }.start();
     }
@@ -895,16 +898,11 @@
      */
     @Deprecated
     public AccountManagerFuture<Bundle> getAuthToken(
-            final Account account, final String authTokenType, final boolean notifyAuthFailure,
+            final Account account, final String authTokenType, 
+            final boolean notifyAuthFailure,
             AccountManagerCallback<Bundle> callback, Handler handler) {
-        if (account == null) throw new IllegalArgumentException("account is null");
-        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
-        return new AmsTask(null, handler, callback) {
-            public void doWork() throws RemoteException {
-                mService.getAuthToken(mResponse, account, authTokenType,
-                        notifyAuthFailure, false /* expectActivityLaunch */, null /* options */);
-            }
-        }.start();
+        return getAuthToken(account, authTokenType, null, notifyAuthFailure, callback, 
+                handler);
     }
 
     /**
@@ -978,15 +976,18 @@
      * account before requesting an auth token.
      */
     public AccountManagerFuture<Bundle> getAuthToken(
-            final Account account, final String authTokenType,
-            final Bundle options, final boolean notifyAuthFailure,
+            final Account account, final String authTokenType, final Bundle options,
+            final boolean notifyAuthFailure,
             AccountManagerCallback<Bundle> callback, Handler handler) {
+
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        final Bundle optionsIn = options == null ? new Bundle() : options;
+        optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
         return new AmsTask(null, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.getAuthToken(mResponse, account, authTokenType,
-                        notifyAuthFailure, false /* expectActivityLaunch */, options);
+                        notifyAuthFailure, false /* expectActivityLaunch */, optionsIn);
             }
         }.start();
     }
@@ -1044,10 +1045,14 @@
             final Bundle addAccountOptions,
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        final Bundle options = (addAccountOptions == null) ? new Bundle() :
+            addAccountOptions;
+        options.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName());
+
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.addAcount(mResponse, accountType, authTokenType,
-                        requiredFeatures, activity != null, addAccountOptions);
+                        requiredFeatures, activity != null, options);
             }
         }.start();
     }
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 20d5b96..173da8d 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -16,10 +16,6 @@
 
 package android.accounts;
 
-import com.android.internal.R;
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.TelephonyIntents;
-
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -51,13 +47,13 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.internal.R;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -924,9 +920,6 @@
         if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
-        final int callerUid = Binder.getCallingUid();
-        final int callerPid = Binder.getCallingPid();
-
         AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
             mAuthenticatorCache.getServiceInfo(
                     AuthenticatorDescription.newKey(account.type));
@@ -934,20 +927,19 @@
             authenticatorInfo != null && authenticatorInfo.type.customTokens;
 
         // skip the check if customTokens
+        final int callerUid = Binder.getCallingUid();
         final boolean permissionGranted = customTokens ||
             permissionIsGranted(account, authTokenType, callerUid);
 
         final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
             loginOptionsIn;
-        if (customTokens) {
-            // let authenticator know the identity of the caller
-            loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
-            loginOptions.putInt(AccountManager.KEY_CALLER_PID, callerPid);
-            if (notifyOnAuthFailure) {
-                loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
-            }
+        // let authenticator know the identity of the caller
+        loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
+        loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
+        if (notifyOnAuthFailure) {
+            loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
         }
-
+        
         long identityToken = clearCallingIdentity();
         try {
             // if the caller has permission, do the peek. otherwise go the more expensive
@@ -1120,7 +1112,7 @@
 
     public void addAcount(final IAccountManagerResponse response, final String accountType,
             final String authTokenType, final String[] requiredFeatures,
-            final boolean expectActivityLaunch, final Bundle options) {
+            final boolean expectActivityLaunch, final Bundle optionsIn) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "addAccount: accountType " + accountType
                     + ", response " + response
@@ -1133,6 +1125,13 @@
         if (response == null) throw new IllegalArgumentException("response is null");
         if (accountType == null) throw new IllegalArgumentException("accountType is null");
         checkManageAccountsPermission();
+
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+        final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
+        options.putInt(AccountManager.KEY_CALLER_UID, uid);
+        options.putInt(AccountManager.KEY_CALLER_PID, pid);
+
         long identityToken = clearCallingIdentity();
         try {
             new Session(response, accountType, expectActivityLaunch,
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 0d4a067..be00aa5 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -915,6 +915,7 @@
                     com.android.internal.R.styleable.ActionBar_LayoutParams);
             gravity = a.getInt(
                     com.android.internal.R.styleable.ActionBar_LayoutParams_layout_gravity, -1);
+            a.recycle();
         }
 
         public LayoutParams(int width, int height) {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c61e32f..e7b844c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -92,6 +92,7 @@
 
     private String mArchiveSourcePath;
     private String[] mSeparateProcesses;
+    private boolean mOnlyCoreApps;
     private static final int SDK_VERSION = Build.VERSION.SDK_INT;
     private static final String SDK_CODENAME = "REL".equals(Build.VERSION.CODENAME)
             ? null : Build.VERSION.CODENAME;
@@ -180,6 +181,10 @@
         mSeparateProcesses = procs;
     }
 
+    public void setOnlyCoreApps(boolean onlyCoreApps) {
+        mOnlyCoreApps = onlyCoreApps;
+    }
+
     private static final boolean isPackageFilename(String name) {
         return name.endsWith(".apk");
     }
@@ -433,18 +438,22 @@
 
 
         if (pkg == null) {
-            if (errorException != null) {
-                Slog.w(TAG, mArchiveSourcePath, errorException);
-            } else {
-                Slog.w(TAG, mArchiveSourcePath + " (at "
-                        + parser.getPositionDescription()
-                        + "): " + errorText[0]);
+            // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED
+            // just means to skip this app so don't make a fuss about it.
+            if (!mOnlyCoreApps || mParseError != PackageManager.INSTALL_SUCCEEDED) {
+                if (errorException != null) {
+                    Slog.w(TAG, mArchiveSourcePath, errorException);
+                } else {
+                    Slog.w(TAG, mArchiveSourcePath + " (at "
+                            + parser.getPositionDescription()
+                            + "): " + errorText[0]);
+                }
+                if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                }
             }
             parser.close();
             assmgr.close();
-            if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
-                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-            }
             return null;
         }
 
@@ -782,6 +791,14 @@
         }
         int type;
 
+        if (mOnlyCoreApps) {
+            boolean core = attrs.getAttributeBooleanValue(null, "coreApp", false);
+            if (!core) {
+                mParseError = PackageManager.INSTALL_SUCCEEDED;
+                return null;
+            }
+        }
+
         final Package pkg = new Package(pkgName);
         boolean foundApp = false;
         
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d7f901a..4f19010 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -72,6 +72,7 @@
     static final String TAG = "Resources";
     private static final boolean DEBUG_LOAD = false;
     private static final boolean DEBUG_CONFIG = false;
+    private static final boolean DEBUG_ATTRIBUTES_CACHE = false;
     private static final boolean TRACE_FOR_PRELOAD = false;
     private static final boolean TRACE_FOR_MISS_PRELOAD = false;
 
@@ -104,6 +105,7 @@
     private boolean mPreloading;
 
     /*package*/ TypedArray mCachedStyledAttributes = null;
+    RuntimeException mLastRetrievedAttrs = null;
 
     private int mLastCachedXmlBlockIndex = -1;
     private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
@@ -2167,6 +2169,10 @@
             TypedArray attrs = mCachedStyledAttributes;
             if (attrs != null) {
                 mCachedStyledAttributes = null;
+                if (DEBUG_ATTRIBUTES_CACHE) {
+                    mLastRetrievedAttrs = new RuntimeException("here");
+                    mLastRetrievedAttrs.fillInStackTrace();
+                }
 
                 attrs.mLength = len;
                 int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
@@ -2177,6 +2183,15 @@
                 attrs.mIndices = new int[1+len];
                 return attrs;
             }
+            if (DEBUG_ATTRIBUTES_CACHE) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                if (mLastRetrievedAttrs != null) {
+                    Log.i(TAG, "Allocated new TypedArray of " + len + " in " + this, here);
+                    Log.i(TAG, "Last retrieved attributes here", mLastRetrievedAttrs);
+                }
+                mLastRetrievedAttrs = here;
+            }
             return new TypedArray(this,
                     new int[len*AssetManager.STYLE_NUM_ENTRIES],
                     new int[1+len], len);
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index d07d899..d8ac31f 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -29,6 +29,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.MathUtils;
 
 import java.io.CharArrayWriter;
 import java.io.DataInputStream;
@@ -207,6 +208,34 @@
     }
 
     /**
+     * Return index of bucket that contains or is immediately before the
+     * requested time.
+     */
+    public int getIndexBefore(long time) {
+        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
+        if (index < 0) {
+            index = (~index) - 1;
+        } else {
+            index -= 1;
+        }
+        return MathUtils.constrain(index, 0, bucketCount - 1);
+    }
+
+    /**
+     * Return index of bucket that contains or is immediately after the
+     * requested time.
+     */
+    public int getIndexAfter(long time) {
+        int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time);
+        if (index < 0) {
+            index = ~index;
+        } else {
+            index += 1;
+        }
+        return MathUtils.constrain(index, 0, bucketCount - 1);
+    }
+
+    /**
      * Return specific stats entry.
      */
     public Entry getValues(int i, Entry recycle) {
@@ -247,7 +276,8 @@
 
         // distribute data usage into buckets
         long duration = end - start;
-        for (int i = bucketCount - 1; i >= 0; i--) {
+        final int startIndex = getIndexAfter(end);
+        for (int i = startIndex; i >= 0; i--) {
             final long curStart = bucketStart[i];
             final long curEnd = curStart + bucketDuration;
 
@@ -406,7 +436,8 @@
         entry.txPackets = txPackets != null ? 0 : UNKNOWN;
         entry.operations = operations != null ? 0 : UNKNOWN;
 
-        for (int i = bucketCount - 1; i >= 0; i--) {
+        final int startIndex = getIndexAfter(end);
+        for (int i = startIndex; i >= 0; i--) {
             final long curStart = bucketStart[i];
             final long curEnd = curStart + bucketDuration;
 
@@ -417,8 +448,14 @@
 
             // include full value for active buckets, otherwise only fractional
             final boolean activeBucket = curStart < now && curEnd > now;
-            final long overlap = activeBucket ? bucketDuration
-                    : Math.min(curEnd, end) - Math.max(curStart, start);
+            final long overlap;
+            if (activeBucket) {
+                overlap = bucketDuration;
+            } else {
+                final long overlapEnd = curEnd < end ? curEnd : end;
+                final long overlapStart = curStart > start ? curStart : start;
+                overlap = overlapEnd - overlapStart;
+            }
             if (overlap <= 0) continue;
 
             // integer math each time is faster than floating point
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 68a6b3e..a52d48e 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -723,7 +723,7 @@
         float ret = 0;
 
         int contextLen = contextEnd - contextStart;
-        if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) {
+        if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
             int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
             if (mCharsValid) {
                 ret = wp.getTextRunAdvances(mChars, start, runLen,
@@ -753,7 +753,7 @@
                 wp.setColor(previousColor);
             }
 
-            if (wp.underlineCount != 0) {
+            if (wp.underlineColor != 0) {
                 // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h
                 float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize();
 
@@ -764,11 +764,8 @@
                 wp.setStyle(Paint.Style.FILL);
                 wp.setAntiAlias(true);
 
-                for (int i = 0; i < wp.underlineCount; i++) {
-                    wp.setColor(wp.underlineColors[i]);
-                    c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i],
-                            wp);
-                }
+                wp.setColor(wp.underlineColor);
+                c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp);
 
                 wp.setStyle(previousStyle);
                 wp.setColor(previousColor);
diff --git a/core/java/android/text/TextPaint.java b/core/java/android/text/TextPaint.java
index afd9892..0447117 100644
--- a/core/java/android/text/TextPaint.java
+++ b/core/java/android/text/TextPaint.java
@@ -24,8 +24,6 @@
  */
 public class TextPaint extends Paint {
 
-    private static final int DEFAULT_UNDERLINE_SIZE = 3;
-
     // Special value 0 means no background paint
     public int bgColor;
     public int baselineShift;
@@ -36,17 +34,12 @@
      * Special value 0 means no custom underline
      * @hide
      */
-    public int[] underlineColors;
+    public int underlineColor = 0;
     /**
      * Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
      * @hide
      */
-    public float[] underlineThicknesses;
-    /**
-     * The number of underlines currently stored in the array. If 0, no underline is drawn.
-     * @hide
-     */
-    public int underlineCount;
+    public float underlineThickness;
 
     public TextPaint() {
         super();
@@ -72,16 +65,8 @@
         linkColor = tp.linkColor;
         drawableState = tp.drawableState;
         density = tp.density;
-
-        if (tp.underlineColors != null) {
-            if (underlineColors == null || underlineColors.length < tp.underlineCount) {
-                underlineColors = new int[tp.underlineCount];
-                underlineThicknesses = new float[tp.underlineCount];
-            }
-            System.arraycopy(tp.underlineColors, 0, underlineColors, 0, tp.underlineCount);
-            System.arraycopy(tp.underlineThicknesses, 0, underlineThicknesses, 0, tp.underlineCount);
-        }
-        underlineCount = tp.underlineCount;
+        underlineColor = tp.underlineColor;
+        underlineThickness = tp.underlineThickness;
     }
 
     /**
@@ -91,31 +76,7 @@
      * @hide
      */
     public void setUnderlineText(int color, float thickness) {
-        if (color == 0) {
-            // No underline
-            return;
-        }
-
-        if (underlineCount == 0) {
-            underlineColors = new int[DEFAULT_UNDERLINE_SIZE];
-            underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE];
-            underlineColors[underlineCount] = color;
-            underlineThicknesses[underlineCount] = thickness;
-            underlineCount++;
-        } else {
-            if (underlineCount == underlineColors.length) {
-                int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE];
-                float[] newThickness = new float[underlineThicknesses.length
-                        + DEFAULT_UNDERLINE_SIZE];
-                System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length);
-                System.arraycopy(
-                        underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length);
-                underlineColors = newColors;
-                underlineThicknesses = newThickness;
-            }
-            underlineColors[underlineCount] = color;
-            underlineThicknesses[underlineCount] = thickness;
-            underlineCount++;
-        }
+        underlineColor = color;
+        underlineThickness = thickness;
     }
 }
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 51e9d7d..1379dd2 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -108,7 +108,8 @@
     /**
      * @param context Context for the application
      * @param locale locale Locale of the suggestions
-     * @param suggestions Suggestions for the string under the span
+     * @param suggestions Suggestions for the string under the span. Only the first up to
+     * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered.
      * @param flags Additional flags indicating how this span is handled in TextView
      * @param notificationTargetClass if not null, this class will get notified when the user
      * selects one of the suggestions.
@@ -258,10 +259,16 @@
 
     @Override
     public void updateDrawState(TextPaint tp) {
-        if ((mFlags & FLAG_MISSPELLED) != 0) {
-            tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
-        } else if ((mFlags & FLAG_EASY_CORRECT) != 0) {
-            tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+        final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
+        final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+        if (easy) {
+            if (!misspelled) {
+                tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+            } else if (tp.underlineColor == 0) {
+                // Spans are rendered in an arbitrary order. Since misspelled is less prioritary
+                // than just easy, do not apply misspelled if an easy (or a mispelled) has been set
+                tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+            }
         }
     }
 
@@ -272,8 +279,15 @@
      */
     public int getUnderlineColor() {
         // The order here should match what is used in updateDrawState
-        if ((mFlags & FLAG_MISSPELLED) != 0) return mMisspelledUnderlineColor;
-        if ((mFlags & FLAG_EASY_CORRECT) != 0) return mEasyCorrectUnderlineColor;
+        final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
+        final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
+        if (easy) {
+            if (!misspelled) {
+                return mEasyCorrectUnderlineColor;
+            } else {
+                return mMisspelledUnderlineColor;
+            }
+        }
         return 0;
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index eedf19f..1cc428b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -27,7 +27,6 @@
 import android.graphics.Interpolator;
 import android.graphics.LinearGradient;
 import android.graphics.Matrix;
-import android.graphics.Matrix.ScaleToFit;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -2272,8 +2271,6 @@
      */
     int mOldHeightMeasureSpec = Integer.MIN_VALUE;
 
-    private Resources mResources = null;
-
     private Drawable mBGDrawable;
 
     private int mBackgroundResource;
@@ -2336,6 +2333,8 @@
      */
     protected Context mContext;
 
+    private final Resources mResources;
+
     private ScrollabilityCache mScrollCache;
 
     private int[] mDrawableState = null;
@@ -2552,6 +2551,11 @@
     private boolean mSendingHoverAccessibilityEvents;
 
     /**
+     * Delegate for injecting accessiblity functionality.
+     */
+    AccessibilityDelegate mAccessibilityDelegate;
+
+    /**
      * Text direction is inherited thru {@link ViewGroup}
      * @hide
      */
@@ -3012,6 +3016,8 @@
             }
         }
 
+        a.recycle();
+
         setOverScrollMode(overScrollMode);
 
         if (background != null) {
@@ -3069,14 +3075,13 @@
         }
 
         computeOpaqueFlags();
-
-        a.recycle();
     }
 
     /**
      * Non-public constructor for use in testing
      */
     View() {
+        mResources = null;
     }
 
     /**
@@ -3774,14 +3779,34 @@
      * and last calls
      * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
      * on its parent to resuest sending of the event to interested parties.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is
+     * responsible for handling this call.
+     * </p>
      *
      * @param eventType The type of the event to send.
      *
      * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)
+     * @see AccessibilityDelegate
      */
     public void sendAccessibilityEvent(int eventType) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.sendAccessibilityEvent(this, eventType);
+        } else {
+            sendAccessibilityEventInternal(eventType);
+        }
+    }
+
+    /**
+     * @see #sendAccessibilityEvent(int)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void sendAccessibilityEventInternal(int eventType) {
         if (AccessibilityManager.getInstance(mContext).isEnabled()) {
             sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType));
         }
@@ -3790,13 +3815,32 @@
     /**
      * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but
      * takes as an argument an empty {@link AccessibilityEvent} and does not
-     * perfrom a check whether accessibility is enabled.
+     * perform a check whether accessibility is enabled.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param event The event to send.
      *
      * @see #sendAccessibilityEvent(int)
      */
     public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+           mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event);
+        } else {
+            sendAccessibilityEventUncheckedInternal(event);
+        }
+    }
+
+    /**
+     * @see #sendAccessibilityEventUnchecked(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) {
         if (!isShown()) {
             return;
         }
@@ -3811,18 +3855,36 @@
      * to its children for adding their text content to the event. Note that the
      * event text is populated in a separate dispatch path since we add to the
      * event not only the text of the source but also the text of all its descendants.
-     * </p>
      * A typical implementation will call
      * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view
      * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
      * on each child. Override this method if custom population of the event text
      * content is required.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param event The event.
      *
      * @return True if the event population was completed.
      */
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event);
+        } else {
+            return dispatchPopulateAccessibilityEventInternal(event);
+        }
+    }
+
+    /**
+     * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         onPopulateAccessibilityEvent(event);
         return false;
     }
@@ -3845,6 +3907,12 @@
      *     event.getText().add(selectedDateUtterance);
      * }
      * </code></pre></p>
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param event The accessibility event which to populate.
      *
@@ -3852,13 +3920,27 @@
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event);
+        } else {
+            onPopulateAccessibilityEventInternal(event);
+        }
     }
 
     /**
-     * Initializes an {@link AccessibilityEvent} with information about the
-     * the type of the event and this View which is the event source. In other
-     * words, the source of an accessibility event is the view whose state
-     * change triggered firing the event.
+     * @see #onPopulateAccessibilityEvent(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
+
+    }
+
+    /**
+     * Initializes an {@link AccessibilityEvent} with information about
+     * this View which is the event source. In other words, the source of
+     * an accessibility event is the view whose state change triggered firing
+     * the event.
      * <p>
      * Example: Setting the password property of an event in addition
      *          to properties set by the super implementation.
@@ -3868,12 +3950,32 @@
      *    event.setPassword(true);
      * }
      * </code></pre></p>
-     * @param event The event to initialeze.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
+     *
+     * @param event The event to initialize.
      *
      * @see #sendAccessibilityEvent(int)
      * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent)
      */
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event);
+        } else {
+            onInitializeAccessibilityEventInternal(event);
+        }
+    }
+
+    /**
+     * @see #onInitializeAccessibilityEvent(AccessibilityEvent)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
         event.setSource(this);
         event.setClassName(getClass().getName());
         event.setPackageName(getContext().getPackageName());
@@ -3942,9 +4044,29 @@
      * Subclasses should override this method, call the super implementation,
      * and set additional attributes.
      * </p>
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}
+     * is responsible for handling this call.
+     * </p>
+     *
      * @param info The instance to initialize.
      */
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info);
+        } else {
+            onInitializeAccessibilityNodeInfoInternal(info);
+        }
+    }
+
+    /**
+     * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+     *
+     * Note: Called from the default {@link AccessibilityDelegate}.
+     */
+    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         Rect bounds = mAttachInfo.mTmpInvalRect;
         getDrawingRect(bounds);
         info.setBoundsInParent(bounds);
@@ -3988,6 +4110,19 @@
     }
 
     /**
+     * Sets a delegate for implementing accessibility support via compositon as
+     * opposed to inheritance. The delegate's primary use is for implementing
+     * backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
+     *
+     * @param delegate The delegate instance.
+     *
+     * @see AccessibilityDelegate
+     */
+    public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
+        mAccessibilityDelegate = delegate;
+    }
+
+    /**
      * Gets the unique identifier of this view on the screen for accessibility purposes.
      * If this {@link View} is not attached to any window, {@value #NO_ID} is returned.
      *
@@ -10192,7 +10327,7 @@
 
     /**
      * Setting a solid background color for the drawing cache's bitmaps will improve
-     * perfromance and memory usage. Note, though that this should only be used if this
+     * performance and memory usage. Note, though that this should only be used if this
      * view will always be drawn on top of a solid color.
      *
      * @param color The background color to use for the drawing cache's bitmap
@@ -14417,4 +14552,205 @@
             mIsPending = false;
         }
     }
+
+    /**
+     * <p>
+     * This class represents a delegate that can be registered in a {@link View}
+     * to enhance accessibility support via composition rather via inheritance.
+     * It is specifically targeted to widget developers that extend basic View
+     * classes i.e. classes in package android.view, that would like their
+     * applications to be backwards compatible.
+     * </p>
+     * <p>
+     * A scenario in which a developer would like to use an accessibility delegate
+     * is overriding a method introduced in a later API version then the minimal API
+     * version supported by the application. For example, the method
+     * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available
+     * in API version 4 when the accessibility APIs were first introduced. If a
+     * developer would like his application to run on API version 4 devices (assuming
+     * all other APIs used by the application are version 4 or lower) and take advantage
+     * of this method, instead of overriding the method which would break the application's
+     * backwards compatibility, he can override the corresponding method in this
+     * delegate and register the delegate in the target View if the API version of
+     * the system is high enough i.e. the API version is same or higher to the API
+     * version that introduced
+     * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}.
+     * </p>
+     * <p>
+     * Here is an example implementation:
+     * </p>
+     * <code><pre><p>
+     * if (Build.VERSION.SDK_INT >= 14) {
+     *     // If the API version is equal of higher than the version in
+     *     // which onInitializeAccessibilityNodeInfo was introduced we
+     *     // register a delegate with a customized implementation.
+     *     View view = findViewById(R.id.view_id);
+     *     view.setAccessibilityDelegate(new AccessibilityDelegate() {
+     *         public void onInitializeAccessibilityNodeInfo(View host,
+     *                 AccessibilityNodeInfo info) {
+     *             // Let the default implementation populate the info.
+     *             super.onInitializeAccessibilityNodeInfo(host, info);
+     *             // Set some other information.
+     *             info.setEnabled(host.isEnabled());
+     *         }
+     *     });
+     * }
+     * </code></pre></p>
+     * <p>
+     * This delegate contains methods that correspond to the accessibility methods
+     * in View. If a delegate has been specified the implementation in View hands
+     * off handling to the corresponding method in this delegate. The default
+     * implementation the delegate methods behaves exactly as the corresponding
+     * method in View for the case of no accessibility delegate been set. Hence,
+     * to customize the behavior of a View method, clients can override only the
+     * corresponding delegate method without altering the behavior of the rest
+     * accessibility related methods of the host view.
+     * </p>
+     */
+    public static class AccessibilityDelegate {
+
+        /**
+         * Sends an accessibility event of the given type. If accessibility is not
+         * enabled this method has no effect.
+         * <p>
+         * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
+         *  View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
+         * been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param eventType The type of the event to send.
+         *
+         * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
+         */
+        public void sendAccessibilityEvent(View host, int eventType) {
+            host.sendAccessibilityEventInternal(eventType);
+        }
+
+        /**
+         * Sends an accessibility event. This method behaves exactly as
+         * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an
+         * empty {@link AccessibilityEvent} and does not perform a check whether
+         * accessibility is enabled.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+         *  View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The event to send.
+         *
+         * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+         *      View#sendAccessibilityEventUnchecked(AccessibilityEvent)
+         */
+        public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
+            host.sendAccessibilityEventUncheckedInternal(event);
+        }
+
+        /**
+         * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then
+         * to its children for adding their text content to the event.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+         *  View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The event.
+         * @return True if the event population was completed.
+         *
+         * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+         *      View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
+         */
+        public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+            return host.dispatchPopulateAccessibilityEventInternal(event);
+        }
+
+        /**
+         * Gives a chance to the host View to populate the accessibility event with its
+         * text content.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)
+         *  View#onPopulateAccessibilityEvent(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The accessibility event which to populate.
+         *
+         * @see View#onPopulateAccessibilityEvent(AccessibilityEvent)
+         *      View#onPopulateAccessibilityEvent(AccessibilityEvent)
+         */
+        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+            host.onPopulateAccessibilityEventInternal(event);
+        }
+
+        /**
+         * Initializes an {@link AccessibilityEvent} with information about the
+         * the host View which is the event source.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)
+         *  View#onInitializeAccessibilityEvent(AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param event The event to initialize.
+         *
+         * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
+         *      View#onInitializeAccessibilityEvent(AccessibilityEvent)
+         */
+        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+            host.onInitializeAccessibilityEventInternal(event);
+        }
+
+        /**
+         * Initializes an {@link AccessibilityNodeInfo} with information about the host view.
+         * <p>
+         * The default implementation behaves as
+         * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+         *  View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param info The instance to initialize.
+         *
+         * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+         *      View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
+         */
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+            host.onInitializeAccessibilityNodeInfoInternal(info);
+        }
+
+        /**
+         * Called when a child of the host View has requested sending an
+         * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
+         * to augment the event.
+         * <p>
+         * The default implementation behaves as
+         * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+         *  ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for
+         * the case of no accessibility delegate been set.
+         * </p>
+         *
+         * @param host The View hosting the delegate.
+         * @param child The child which requests sending the event.
+         * @param event The event to be sent.
+         * @return True if the event should be sent
+         *
+         * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+         *      ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+         */
+        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+                AccessibilityEvent event) {
+            return host.onRequestSendAccessibilityEventInternal(child, event);
+        }
+    }
 }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0e420d6..1bd0782 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -34,6 +34,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.View.AccessibilityDelegate;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Animation;
@@ -606,6 +607,12 @@
     /**
      * Called when a child has requested sending an {@link AccessibilityEvent} and
      * gives an opportunity to its parent to augment the event.
+     * <p>
+     * If an {@link AccessibilityDelegate} has been specified via calling
+     * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its
+     * {@link AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
+     * is responsible for handling this call.
+     * </p>
      *
      * @param child The child which requests sending the event.
      * @param event The event to be sent.
@@ -614,6 +621,19 @@
      * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
      */
     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (mAccessibilityDelegate != null) {
+            return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
+        } else {
+            return onRequestSendAccessibilityEventInternal(child, event);
+        }
+    }
+
+    /**
+     * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
+     *
+     * Note: Called from the default {@link View.AccessibilityDelegate}.
+     */
+    boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
         return true;
     }
 
@@ -2142,9 +2162,9 @@
     }
 
     @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         // We first get a chance to populate the event.
-        onPopulateAccessibilityEvent(event);
+        super.dispatchPopulateAccessibilityEventInternal(event);
         // Let our children have a shot in populating the event.
         for (int i = 0, count = getChildCount(); i < count; i++) {
             View child = getChildAt(i);
@@ -2159,8 +2179,8 @@
     }
 
     @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
+    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfoInternal(info);
         // If the view is not the topmost one in the view hierarchy and it is
         // marked as the logical root of a view hierarchy, do not go any deeper.
         if ((!(getParent() instanceof ViewRootImpl)) && (mPrivateFlags & IS_ROOT_NAMESPACE) != 0) {
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index c1eec6f..0d57c9b 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -232,11 +232,6 @@
         setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
         setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));
 
-        final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
-        if (resID > 0) {
-            setInterpolator(context, resID);
-        }
-
         setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
         setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));
 
@@ -245,10 +240,16 @@
         setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
 
         setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
-        
-        ensureInterpolator();
+
+        final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
 
         a.recycle();
+
+        if (resID > 0) {
+            setInterpolator(context, resID);
+        }
+
+        ensureInterpolator();
     }
 
     @Override
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 77f6776..9c44138 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -643,10 +643,10 @@
 
     /**
      * Set whether the WebView will enable smooth transition while panning or
-     * zooming. If it is true, WebView will choose a solution to maximize the
-     * performance. e.g. the WebView's content may not be updated during the
-     * transition. If it is false, WebView will keep its fidelity. The default
-     * value is false.
+     * zooming or while the window hosting the WebView does not have focus.
+     * If it is true, WebView will choose a solution to maximize the performance.
+     * e.g. the WebView's content may not be updated during the transition.
+     * If it is false, WebView will keep its fidelity. The default value is false.
      */
     public void setEnableSmoothTransition(boolean enable) {
         mEnableSmoothTransition = enable;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 47abbc2..065beb1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -908,6 +908,9 @@
     // used for serializing asynchronously handled touch events.
     private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
 
+    // Used to track whether picture updating was paused due to a window focus change.
+    private boolean mPictureUpdatePausedForFocusChange = false;
+
     // Used to notify listeners of a new picture.
     private PictureListener mPictureListener;
     /**
@@ -5570,8 +5573,20 @@
         setActive(hasWindowFocus);
         if (hasWindowFocus) {
             JWebCoreJavaBridge.setActiveWebView(this);
+            if (mPictureUpdatePausedForFocusChange) {
+                WebViewCore.resumeUpdatePicture(mWebViewCore);
+                nativeSetIsScrolling(false);
+                mPictureUpdatePausedForFocusChange = false;
+            }
         } else {
             JWebCoreJavaBridge.removeActiveWebView(this);
+            final WebSettings settings = getSettings();
+            if (settings != null && settings.enableSmoothTransition() &&
+                    mWebViewCore != null && !WebViewCore.isUpdatePicturePaused(mWebViewCore)) {
+                WebViewCore.pauseUpdatePicture(mWebViewCore);
+                nativeSetIsScrolling(true);
+                mPictureUpdatePausedForFocusChange = true;
+            }
         }
         super.onWindowFocusChanged(hasWindowFocus);
     }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c61bd48..843a624 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -2107,6 +2107,10 @@
         }
     }
 
+    static boolean isUpdatePicturePaused(WebViewCore core) {
+        return core != null ? core.mDrawIsPaused : false;
+    }
+
     //////////////////////////////////////////////////////////////////////////
 
     private void restoreState(int index) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d7fb7a0..353d83c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3774,6 +3774,10 @@
                 }
                 // Fall through
             case TOUCH_MODE_FLING: {
+                if (mDataChanged) {
+                    layoutChildren();
+                }
+
                 if (mItemCount == 0 || getChildCount() == 0) {
                     endFling();
                     return;
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 2d10bbe..72db8e8 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -896,6 +896,7 @@
 
     @Override
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
         // We send selection events only from AdapterView to avoid
         // generation of such event for each child.
         getSelectedView().dispatchPopulateAccessibilityEvent(event);
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 7598e54..0a54743 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -26,6 +26,7 @@
 import android.view.Gravity;
 import android.view.ViewDebug;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 
 /**
@@ -231,4 +232,10 @@
             event.getText().add(mContext.getString(R.string.radiobutton_not_selected));
         }
     }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setChecked(mChecked);
+    }
 }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b92130d..a5d6c9a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -212,6 +212,7 @@
 
     @Override
     public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        super.onPopulateAccessibilityEvent(event);
         CharSequence contentDescription = getContentDescription();
         if (!TextUtils.isEmpty(contentDescription)) {
             event.getText().add(contentDescription);
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 191c4ca..80bfe99 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -489,6 +489,7 @@
     public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
         // this class fires events only when tabs are focused or selected
         if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && isFocused()) {
+            event.recycle();
             return;
         }
         super.sendAccessibilityEventUnchecked(event);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 40d85d8..ecd99b2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -461,10 +461,6 @@
         mMovement = getDefaultMovementMethod();
         mTransformation = null;
 
-        TypedArray a =
-            context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
-
         int textColorHighlight = 0;
         ColorStateList textColor = null;
         ColorStateList textColorHint = null;
@@ -474,18 +470,23 @@
         int styleIndex = -1;
         boolean allCaps = false;
 
+        final Resources.Theme theme = context.getTheme();
+
         /*
          * Look the appearance up without checking first if it exists because
          * almost every TextView has one and it greatly simplifies the logic
          * to be able to parse the appearance first and then let specific tags
          * for this View override it.
          */
+        TypedArray a = theme.obtainStyledAttributes(
+                    attrs, com.android.internal.R.styleable.TextViewAppearance, defStyle, 0);
         TypedArray appearance = null;
-        int ap = a.getResourceId(com.android.internal.R.styleable.TextView_textAppearance, -1);
+        int ap = a.getResourceId(
+                com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
+        a.recycle();
         if (ap != -1) {
-            appearance = context.obtainStyledAttributes(ap,
-                                com.android.internal.R.styleable.
-                                TextAppearance);
+            appearance = theme.obtainStyledAttributes(
+                    ap, com.android.internal.R.styleable.TextAppearance);
         }
         if (appearance != null) {
             int n = appearance.getIndexCount();
@@ -552,6 +553,9 @@
         boolean password = false;
         int inputType = EditorInfo.TYPE_NULL;
 
+        a = theme.obtainStyledAttributes(
+                    attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
+
         int n = a.getIndexCount();
         for (int i = 0; i < n; i++) {
             int attr = a.getIndex(i);
@@ -9556,6 +9560,9 @@
         private int mNumberOfSuggestions;
         private boolean mCursorWasVisibleBeforeSuggestions;
         private SuggestionAdapter mSuggestionsAdapter;
+        private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
+        private final HashMap<SuggestionSpan, Integer> mSpansLengths;
+
 
         private class CustomPopupWindow extends PopupWindow {
             public CustomPopupWindow(Context context, int defStyle) {
@@ -9581,6 +9588,8 @@
 
         public SuggestionsPopupWindow() {
             mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+            mSuggestionSpanComparator = new SuggestionSpanComparator();
+            mSpansLengths = new HashMap<SuggestionSpan, Integer>();
         }
 
         @Override
@@ -9659,6 +9668,26 @@
             }
         }
 
+        private class SuggestionSpanComparator implements Comparator<SuggestionSpan> {
+            public int compare(SuggestionSpan span1, SuggestionSpan span2) {
+                final int flag1 = span1.getFlags();
+                final int flag2 = span2.getFlags();
+                if (flag1 != flag2) {
+                    // The order here should match what is used in updateDrawState
+                    final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+                    final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
+                    final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+                    final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
+                    if (easy1 && !misspelled1) return -1;
+                    if (easy2 && !misspelled2) return 1;
+                    if (misspelled1) return -1;
+                    if (misspelled2) return 1;
+                }
+
+                return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
+            }
+        }
+
         /**
          * Returns the suggestion spans that cover the current cursor position. The suggestion
          * spans are sorted according to the length of text that they are attached to.
@@ -9668,24 +9697,16 @@
             Spannable spannable = (Spannable) TextView.this.mText;
             SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
 
-            // Cache the span length for performance reason.
-            final HashMap<SuggestionSpan, Integer> spansLengths =
-                    new HashMap<SuggestionSpan, Integer>();
-
+            mSpansLengths.clear();
             for (SuggestionSpan suggestionSpan : suggestionSpans) {
                 int start = spannable.getSpanStart(suggestionSpan);
                 int end = spannable.getSpanEnd(suggestionSpan);
-                spansLengths.put(suggestionSpan, Integer.valueOf(end - start));
+                mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
             }
 
-            // The suggestions are sorted according to the lenght of the text that they cover
-            // (shorter first)
-            Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() {
-                public int compare(SuggestionSpan span1, SuggestionSpan span2) {
-                    return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue();
-                }
-            });
-
+            // The suggestions are sorted according to their types (easy correction first, then
+            // misspelled) and to the length of the text that they cover (shorter first).
+            Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
             return suggestionSpans;
         }
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 7434df3..bbecb6c 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -268,8 +268,10 @@
 
         if (mTabScrollView != null && mIncludeTabs) {
             ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
-            lp.width = LayoutParams.WRAP_CONTENT;
-            lp.height = LayoutParams.MATCH_PARENT;
+            if (lp != null) {
+                lp.width = LayoutParams.WRAP_CONTENT;
+                lp.height = LayoutParams.MATCH_PARENT;
+            }
             mTabScrollView.setAllowCollapse(true);
         }
     }
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 0335ce7..e8933fe 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1562,8 +1562,8 @@
         LOG_AND_FREE_DBUS_ERROR(&err);
     }
 
-    LOGV("... Health Device Code = %d, result = %d", code, result);
     jint code = *(int *) user;
+    LOGV("... Health Device Code = %d, result = %d", code, result);
     env->CallVoidMethod(nat->me,
                         method_onHealthDeviceConnectionResult,
                         code,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 72863a2..9f2eef5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -18,7 +18,7 @@
 */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android" android:sharedUserId="android.uid.system"
+    package="android" coreApp="true" android:sharedUserId="android.uid.system"
     android:sharedUserLabel="@string/android_system_label">
 
     <!-- ================================================ -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fc84f53..c990125 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3177,6 +3177,10 @@
         <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
         <attr name="textAllCaps" />
     </declare-styleable>
+    <declare-styleable name="TextViewAppearance">
+        <!-- Base text color, typeface, size, and style. -->
+        <attr name="textAppearance" />
+    </declare-styleable>
     <declare-styleable name="SuggestionSpan">
         <attr name="textUnderlineColor" />
         <attr name="textUnderlineThickness" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 051ed14..8fd2cd1 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -385,6 +385,9 @@
     <!-- Default value for LED on time when the battery is low on charge in miliseconds -->
     <integer name="config_notificationsBatteryLedOn">125</integer>
 
+    <!-- Is the notification LED intrusive? Used to decide if there should be a disable option -->
+    <bool name="config_intrusiveNotificationLed">false</bool>
+
     <!-- Default value for LED off time when the battery is low on charge in miliseconds -->
     <integer name="config_notificationsBatteryLedOff">2875</integer>
 
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index b888d9a..e1db073 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -407,6 +407,54 @@
         assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
     }
 
+    public void testIndexBeforeAfter() throws Exception {
+        final long BUCKET_SIZE = HOUR_IN_MILLIS;
+        stats = new NetworkStatsHistory(BUCKET_SIZE);
+
+        final long FIRST_START = TEST_START;
+        final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
+        final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
+        final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
+        final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
+        final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
+
+        stats.recordData(FIRST_START, FIRST_END,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+        stats.recordData(SECOND_START, SECOND_END,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+        stats.recordData(THIRD_START, THIRD_END,
+                new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+
+        // should have buckets: 2+1+2
+        assertEquals(5, stats.size());
+
+        assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
+        assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
+        assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
+        assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
+        assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
+        assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
+        assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
+        assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
+        assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
+    }
+
+    private static void assertIndexBeforeAfter(
+            NetworkStatsHistory stats, int before, int after, long time) {
+        assertEquals("unexpected before", before, stats.getIndexBefore(time));
+        assertEquals("unexpected after", after, stats.getIndexAfter(time));
+    }
+
     private static long performVarLong(long before) throws Exception {
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         writeVarLong(new DataOutputStream(out), before);
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 7c4e147..34f9070 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -79,7 +79,7 @@
         float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
         float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
 
-        canvas.rotate(mCurrentDegrees, px, py);
+        canvas.rotate(mCurrentDegrees, px + bounds.left, py + bounds.top);
 
         drawable.draw(canvas);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 8f213da..bf83849 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -26,6 +26,9 @@
 
 namespace android {
 
+// static
+const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
         const sp<AMessage> &notify)
@@ -43,7 +46,8 @@
       mHasAudio(false),
       mHasVideo(false),
       mSyncQueues(false),
-      mPaused(false) {
+      mPaused(false),
+      mLastPositionUpdateUs(-1ll) {
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -190,7 +194,7 @@
     mDrainAudioQueuePending = true;
     sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
     msg->setInt32("generation", mAudioQueueGeneration);
-    msg->post(10000);
+    msg->post();
 }
 
 void NuPlayer::Renderer::signalAudioSinkChanged() {
@@ -198,7 +202,6 @@
 }
 
 void NuPlayer::Renderer::onDrainAudioQueue() {
-
     for (;;) {
         if (mAudioQueue.empty()) {
             break;
@@ -562,6 +565,13 @@
     }
 
     int64_t nowUs = ALooper::GetNowUs();
+
+    if (mLastPositionUpdateUs >= 0
+            && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
+        return;
+    }
+    mLastPositionUpdateUs = nowUs;
+
     int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
 
     sp<AMessage> notify = mNotify->dup();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 2713031..3a641a2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -74,6 +74,8 @@
         status_t mFinalResult;
     };
 
+    static const int64_t kMinPositionUpdateDelayUs;
+
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<AMessage> mNotify;
     List<QueueEntry> mAudioQueue;
@@ -98,6 +100,8 @@
 
     bool mPaused;
 
+    int64_t mLastPositionUpdateUs;
+
     void onDrainAudioQueue();
     void postDrainAudioQueue();
 
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 62d17da..4e46414 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -117,14 +117,12 @@
         }
     }
 
-    int64_t timeUs =
-        (mSampleIndex * 1000000ll * mTrack.mRate) / mTrack.mScale;
-
     off64_t offset;
     size_t size;
     bool isKey;
+    int64_t timeUs;
     status_t err = mExtractor->getSampleInfo(
-            mTrackIndex, mSampleIndex, &offset, &size, &isKey);
+            mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
 
     ++mSampleIndex;
 
@@ -396,6 +394,8 @@
     uint32_t rate = U32LE_AT(&data[20]);
     uint32_t scale = U32LE_AT(&data[24]);
 
+    uint32_t sampleSize = U32LE_AT(&data[44]);
+
     const char *mime = NULL;
     Track::Kind kind = Track::OTHER;
 
@@ -427,6 +427,7 @@
     track->mMeta = meta;
     track->mRate = rate;
     track->mScale = scale;
+    track->mBytesPerSample = sampleSize;
     track->mKind = kind;
     track->mNumSyncSamples = 0;
     track->mThumbnailSampleSize = 0;
@@ -612,11 +613,12 @@
         off64_t offset;
         size_t size;
         bool isKey;
-        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey);
+        int64_t timeUs;
+        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
         if (err != OK) {
             mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
-            err = getSampleInfo(0, 0, &offset, &size, &isKey);
+            err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
             if (err != OK) {
                 return err;
@@ -630,8 +632,9 @@
     for (size_t i = 0; i < mTracks.size(); ++i) {
         Track *track = &mTracks.editItemAt(i);
 
-        int64_t durationUs =
-            (track->mSamples.size() * 1000000ll * track->mRate) / track->mScale;
+        int64_t durationUs;
+        CHECK_EQ((status_t)OK,
+                 getSampleTime(i, track->mSamples.size() - 1, &durationUs));
 
         LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
 
@@ -645,9 +648,10 @@
 
         if (!strncasecmp("video/", mime.c_str(), 6)
                 && track->mThumbnailSampleIndex >= 0) {
-            int64_t thumbnailTimeUs =
-                (track->mThumbnailSampleIndex * 1000000ll * track->mRate)
-                    / track->mScale;
+            int64_t thumbnailTimeUs;
+            CHECK_EQ((status_t)OK,
+                     getSampleTime(i, track->mThumbnailSampleIndex,
+                                   &thumbnailTimeUs));
 
             track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
 
@@ -659,6 +663,21 @@
                 }
             }
         }
+
+        if (track->mBytesPerSample != 0) {
+            // Assume all chunks are the same size for now.
+
+            off64_t offset;
+            size_t size;
+            bool isKey;
+            int64_t sampleTimeUs;
+            CHECK_EQ((status_t)OK,
+                     getSampleInfo(
+                         i, 0,
+                         &offset, &size, &isKey, &sampleTimeUs));
+
+            track->mRate *= size / track->mBytesPerSample;
+        }
     }
 
     mFoundIndex = true;
@@ -720,7 +739,9 @@
     off64_t offset;
     size_t size;
     bool isKey;
-    status_t err = getSampleInfo(trackIndex, 0, &offset, &size, &isKey);
+    int64_t timeUs;
+    status_t err =
+        getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
 
     if (err != OK) {
         return err;
@@ -762,7 +783,8 @@
 
 status_t AVIExtractor::getSampleInfo(
         size_t trackIndex, size_t sampleIndex,
-        off64_t *offset, size_t *size, bool *isKey) {
+        off64_t *offset, size_t *size, bool *isKey,
+        int64_t *sampleTimeUs) {
     if (trackIndex >= mTracks.size()) {
         return -ERANGE;
     }
@@ -801,9 +823,20 @@
 
     *isKey = info.mIsKey;
 
+    *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
+
     return OK;
 }
 
+status_t AVIExtractor::getSampleTime(
+        size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    return getSampleInfo(
+            trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
+}
+
 status_t AVIExtractor::getSampleIndexAtTime(
         size_t trackIndex,
         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 375a94d..b575347 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -54,6 +54,11 @@
         uint32_t mRate;
         uint32_t mScale;
 
+        // If bytes per sample == 0, each chunk represents a single sample,
+        // otherwise each chunk should me a multiple of bytes-per-sample in
+        // size.
+        uint32_t mBytesPerSample;
+
         enum Kind {
             AUDIO,
             VIDEO,
@@ -84,7 +89,11 @@
 
     status_t getSampleInfo(
             size_t trackIndex, size_t sampleIndex,
-            off64_t *offset, size_t *size, bool *isKey);
+            off64_t *offset, size_t *size, bool *isKey,
+            int64_t *sampleTimeUs);
+
+    status_t getSampleTime(
+            size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs);
 
     status_t getSampleIndexAtTime(
             size_t trackIndex,
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 0f47482..319eb8d 100755
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.defcontainer">
+        package="com.android.defcontainer" coreApp="true">
     <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
     <uses-permission android:name="android.permission.ACCESS_ALL_DOWNLOADS"/>
     <uses-permission android:name="android.permission.ASEC_ACCESS"/>
diff --git a/packages/SettingsProvider/AndroidManifest.xml b/packages/SettingsProvider/AndroidManifest.xml
index dd0d064..0719426 100644
--- a/packages/SettingsProvider/AndroidManifest.xml
+++ b/packages/SettingsProvider/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.providers.settings"
+        coreApp="true"
         android:sharedUserId="android.uid.system">
 
     <application android:allowClearUserData="false"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d10911f..a2452c4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.systemui"
+        coreApp="true"
         android:sharedUserId="android.uid.system"
         android:process="system"
         >
diff --git a/packages/SystemUI/res/drawable/notification_list_shadow.xml b/packages/SystemUI/res/drawable/notification_list_shadow.xml
new file mode 100644
index 0000000..7f33153
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_list_shadow.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+    <gradient
+        android:angle="90"
+        android:endColor="@color/notification_list_shadow_top"
+        android:startColor="#00000000"
+        android:type="linear"
+        />
+</shape>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index eae3e52..167d362 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -42,6 +42,7 @@
             <ImageView android:id="@+id/app_thumbnail_image"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:visibility="invisible"
             />
         </FrameLayout>
 
@@ -71,6 +72,7 @@
             android:singleLine="true"
             android:ellipsize="marquee"
             android:visibility="invisible"
+            android:textColor="@color/status_bar_recents_app_label_color"
         />
 
         <TextView android:id="@+id/app_description"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index b14ef59..de80a51 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -40,6 +40,7 @@
             <ImageView android:id="@+id/app_thumbnail_image"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:visibility="invisible"
             />
         </FrameLayout>
 
@@ -67,6 +68,7 @@
             android:layout_marginLeft="@dimen/status_bar_recents_app_label_left_margin"
             android:singleLine="true"
             android:ellipsize="marquee"
+            android:textColor="@color/status_bar_recents_app_label_color"
         />
 
         <View android:id="@+id/recents_callout_line"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index f4be651..07088d5 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -35,6 +35,7 @@
         <ImageView android:id="@+id/app_thumbnail_image"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:visibility="invisible"
         />
     </FrameLayout>
 
@@ -63,6 +64,7 @@
         android:layout_marginTop="32dip"
         android:singleLine="true"
         android:ellipsize="marquee"
+        android:textColor="@color/status_bar_recents_app_label_color"
     />
 
     <View android:id="@+id/recents_callout_line"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0b3fb98..f9f31ca 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -32,6 +32,7 @@
         android:paddingTop="3dp"
         android:paddingBottom="5dp"
         android:paddingRight="3dp"
+        android:background="@drawable/notification_header_bg"
         >
         <com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
             android:textAppearance="@style/TextAppearance.StatusBar.Clock"
@@ -104,12 +105,25 @@
             android:fadingEdge="none"
             android:overScrollMode="ifContentScrolls"
             >
-            <com.android.systemui.statusbar.policy.NotificationRowLayout
-                android:id="@+id/latestItems"
+            <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                systemui:rowHeight="@dimen/notification_height"
+                android:orientation="vertical"
+                >
+                <com.android.systemui.statusbar.policy.NotificationRowLayout
+                    android:id="@+id/latestItems"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    systemui:rowHeight="@dimen/notification_height"
+                    android:background="@color/notification_list_shadow_top"
+                    />
+                <ImageView
+                    android:layout_width="match_parent"
+                    android:layout_height="16dp"
+                    android:src="@drawable/notification_list_shadow"
+                    android:scaleType="fitXY"
                 />
+            </LinearLayout>
         </ScrollView>
 
         <ImageView
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index 894248e..25c0237 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -30,7 +30,7 @@
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="1"
-         android:background="@drawable/status_bar_bg"
+         android:background="@drawable/notification_tracking_bg"
          />
 
     <com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4c222f9..298536b4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -23,5 +23,9 @@
     <drawable name="status_bar_background">#ff000000</drawable>
     <drawable name="status_bar_recents_background">#b3000000</drawable>
     <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
+    <color name="status_bar_recents_app_label_color">#ffffffff</color>
     <drawable name="status_bar_notification_row_background_color">#ff000000</drawable>
+    <drawable name="notification_header_bg">#FF000000</drawable>
+    <drawable name="notification_tracking_bg">#cc111315</drawable>
+    <color name="notification_list_shadow_top">#80000000</color>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 0354fd7..07281d4 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -41,9 +41,10 @@
     public static final int Y = 1;
 
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
-    private int MAX_ESCAPE_ANIMATION_DURATION = 500; // ms
-    private int MAX_DISMISS_VELOCITY = 1000; // dp/sec
-    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 250; // ms
+    private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
+    private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
+    private int MAX_DISMISS_VELOCITY = 2000; // dp/sec
+    private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
 
     public static float ALPHA_FADE_START = 0f; // fraction of thumbnail width
                                                  // where fade starts
@@ -126,7 +127,10 @@
         } else if (pos < viewSize * (1.0f - ALPHA_FADE_START)) {
             result = 1.0f + (viewSize * ALPHA_FADE_START + pos) / fadeSize;
         }
-        return result;
+        // Make .03 alpha the minimum so you always see the item a bit-- slightly below
+        // .03, the item disappears entirely (as if alpha = 0) and that discontinuity looks
+        // a bit jarring
+        return Math.max(0.03f, result);
     }
 
     // invalidate the view's own bounds all the way up the view hierarchy
@@ -186,6 +190,7 @@
                 }
                 break;
             case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
                 mDragging = false;
                 mCurrView = null;
                 mCurrAnimView = null;
@@ -212,7 +217,10 @@
             duration = Math.min(duration,
                                 (int) (Math.abs(newPos - getTranslation(animView)) * 1000f / Math
                                         .abs(velocity)));
+        } else {
+            duration = DEFAULT_ESCAPE_ANIMATION_DURATION;
         }
+
         ObjectAnimator anim = createTranslationAnimation(animView, newPos);
         anim.setInterpolator(new LinearInterpolator());
         anim.setDuration(duration);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index fc03a27..1c9d80d 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -44,15 +44,6 @@
     private SwipeHelper mSwipeHelper;
     private RecentsScrollViewPerformanceHelper mPerformanceHelper;
 
-    private OnLongClickListener mOnLongClick = new OnLongClickListener() {
-        public boolean onLongClick(View v) {
-            final View anchorView = v.findViewById(R.id.app_description);
-            final View thumbnailView = v.findViewById(R.id.app_thumbnail);
-            mCallback.handleLongPress(v, anchorView, thumbnailView);
-            return true;
-        }
-    };
-
     public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
@@ -69,8 +60,6 @@
         mLinearLayout.removeAllViews();
         for (int i = 0; i < mAdapter.getCount(); i++) {
             final View view = mAdapter.getView(i, null, mLinearLayout);
-            view.setLongClickable(true);
-            view.setOnLongClickListener(mOnLongClick);
 
             if (mPerformanceHelper != null) {
                 mPerformanceHelper.addViewCallback(view);
@@ -81,18 +70,30 @@
                     mCallback.dismiss();
                 }
             });
+            // We don't want a click sound when we dimiss recents
+            view.setSoundEffectsEnabled(false);
 
             OnClickListener launchAppListener = new OnClickListener() {
                 public void onClick(View v) {
                     mCallback.handleOnClick(view);
                 }
             };
+            OnLongClickListener longClickListener = new OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    final View anchorView = view.findViewById(R.id.app_description);
+                    final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+                    mCallback.handleLongPress(view, anchorView, thumbnailView);
+                    return true;
+                }
+            };
             final View thumbnail = view.findViewById(R.id.app_thumbnail);
             thumbnail.setClickable(true);
             thumbnail.setOnClickListener(launchAppListener);
+            thumbnail.setOnLongClickListener(longClickListener);
             final View appTitle = view.findViewById(R.id.app_label);
             appTitle.setClickable(true);
             appTitle.setOnClickListener(launchAppListener);
+            appTitle.setOnLongClickListener(longClickListener);
             mLinearLayout.addView(view);
         }
         // Scroll to end after layout.
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index f7afe3a..0621b22 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -186,12 +186,6 @@
                 holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
                 holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
 
-		/*                StateListDrawable thumbnailForegroundDrawable = new StateListDrawable();
-                thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_pressed },
-                        mPressedDrawable);
-                thumbnailForegroundDrawable.addState(new int[] { android.R.attr.state_selected },
-                        mPressedDrawable);
-			((FrameLayout)holder.thumbnailView).setForeground(thumbnailForegroundDrawable);*/
                 convertView.setTag(holder);
             } else {
                 holder = (ViewHolder) convertView.getTag();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index b12387a..213803c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -43,15 +43,6 @@
     private SwipeHelper mSwipeHelper;
     private RecentsScrollViewPerformanceHelper mPerformanceHelper;
 
-    private OnLongClickListener mOnLongClick = new OnLongClickListener() {
-        public boolean onLongClick(View v) {
-            final View anchorView = v.findViewById(R.id.app_description);
-            final View thumbnailView = v.findViewById(R.id.app_thumbnail);
-            mCallback.handleLongPress(v, anchorView, thumbnailView);
-            return true;
-        }
-    };
-
     public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
         super(context, attrs, 0);
         float densityScale = getResources().getDisplayMetrics().density;
@@ -83,28 +74,39 @@
             }
 
             if (old == null) {
-                view.setClickable(true);
-                view.setOnLongClickListener(mOnLongClick);
                 view.setOnClickListener(new OnClickListener() {
                     public void onClick(View v) {
                         mCallback.dismiss();
                     }
                 });
+                // We don't want a click sound when we dimiss recents
+                view.setSoundEffectsEnabled(false);
 
                 OnClickListener launchAppListener = new OnClickListener() {
                     public void onClick(View v) {
                         mCallback.handleOnClick(view);
                     }
                 };
+                OnLongClickListener longClickListener = new OnLongClickListener() {
+                    public boolean onLongClick(View v) {
+                        final View anchorView = view.findViewById(R.id.app_description);
+                        final View thumbnailView = view.findViewById(R.id.app_thumbnail);
+                        mCallback.handleLongPress(view, anchorView, thumbnailView);
+                        return true;
+                    }
+                };
                 final View thumbnail = view.findViewById(R.id.app_thumbnail);
                 thumbnail.setClickable(true);
                 thumbnail.setOnClickListener(launchAppListener);
+                thumbnail.setOnLongClickListener(longClickListener);
                 final View appTitle = view.findViewById(R.id.app_label);
                 appTitle.setClickable(true);
                 appTitle.setOnClickListener(launchAppListener);
+                appTitle.setOnLongClickListener(longClickListener);
                 final View calloutLine = view.findViewById(R.id.recents_callout_line);
                 calloutLine.setClickable(true);
                 calloutLine.setOnClickListener(launchAppListener);
+                calloutLine.setOnLongClickListener(longClickListener);
                 mLinearLayout.addView(view);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 69e0752..0b65d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1458,9 +1458,10 @@
             Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
                 + mDisabled);
         } else if (CHATTY) {
-            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            if (event.getAction() != MotionEvent.ACTION_MOVE) {
                 Slog.d(TAG, String.format(
-                            "panel: ACTION_DOWN at (%f, %f) mDisabled=0x%08x",
+                            "panel: %s at (%f, %f) mDisabled=0x%08x",
+                            MotionEvent.actionToString(event.getAction()),
                             event.getRawX(), event.getRawY(), mDisabled));
             }
         }
@@ -1469,11 +1470,11 @@
             return false;
         }
 
+        final int action = event.getAction();
         final int statusBarSize = mStatusBarView.getHeight();
         final int hitSize = statusBarSize*2;
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final int y = (int)event.getRawY();
-
+        final int y = (int)event.getRawY();
+        if (action == MotionEvent.ACTION_DOWN) {
             if (!mExpanded) {
                 mViewDelta = statusBarSize - y;
             } else {
@@ -1490,21 +1491,21 @@
                 final int edgeBorder = mEdgeBorder;
                 if (x >= edgeBorder && x < mDisplayMetrics.widthPixels - edgeBorder) {
                     prepareTracking(y, !mExpanded);// opening if we're not already fully visible
-                    mVelocityTracker.addMovement(event);
+                    trackMovement(event);
                 }
             }
         } else if (mTracking) {
-            mVelocityTracker.addMovement(event);
+            trackMovement(event);
             final int minY = statusBarSize + mCloseView.getHeight();
-            if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                int y = (int)event.getRawY();
+            if (action == MotionEvent.ACTION_MOVE) {
                 if (mAnimatingReveal && y < minY) {
                     // nothing
                 } else  {
                     mAnimatingReveal = false;
                     updateExpandedViewPos(y + mViewDelta);
                 }
-            } else if (event.getAction() == MotionEvent.ACTION_UP) {
+            } else if (action == MotionEvent.ACTION_UP
+                    || action == MotionEvent.ACTION_CANCEL) {
                 mVelocityTracker.computeCurrentVelocity(1000);
 
                 float yVel = mVelocityTracker.getYVelocity();
@@ -1531,13 +1532,23 @@
                         vel));
                 }
 
-                performFling((int)event.getRawY(), vel, false);
+                performFling(y + mViewDelta, vel, false);
             }
 
         }
         return false;
     }
 
+    private void trackMovement(MotionEvent event) {
+        // Add movement to velocity tracker using raw screen X and Y coordinates instead
+        // of window coordinates because the window frame may be moving at the same time.
+        float deltaX = event.getRawX() - event.getX();
+        float deltaY = event.getRawY() - event.getY();
+        event.offsetLocation(deltaX, deltaY);
+        mVelocityTracker.addMovement(event);
+        event.offsetLocation(-deltaX, -deltaY);
+    }
+
     @Override // CommandQueue
     public void setSystemUiVisibility(int vis) {
         final int old = mSystemUiVisibility;
@@ -1834,7 +1845,7 @@
                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                PixelFormat.OPAQUE);
+                PixelFormat.TRANSLUCENT);
         if (ActivityManager.isHighEndGfx(mDisplay)) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2714fc5..7e28c4f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -148,7 +148,8 @@
 
             Slog.i(TAG, "Package Manager");
             pm = PackageManagerService.main(context,
-                    factoryTest != SystemServer.FACTORY_TEST_OFF);
+                    factoryTest != SystemServer.FACTORY_TEST_OFF,
+                    false);
 
             ActivityManagerService.setSystemProcess();
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index bfb244b..4e5ca8e 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -221,6 +221,7 @@
 
     final Context mContext;
     final boolean mFactoryTest;
+    final boolean mOnlyCore;
     final boolean mNoDexOpt;
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
@@ -809,8 +810,9 @@
         return false;
     }
 
-    public static final IPackageManager main(Context context, boolean factoryTest) {
-        PackageManagerService m = new PackageManagerService(context, factoryTest);
+    public static final IPackageManager main(Context context, boolean factoryTest,
+            boolean onlyCore) {
+        PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);
         ServiceManager.addService("package", m);
         return m;
     }
@@ -837,7 +839,7 @@
         return res;
     }
 
-    public PackageManagerService(Context context, boolean factoryTest) {
+    public PackageManagerService(Context context, boolean factoryTest, boolean onlyCore) {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                 SystemClock.uptimeMillis());
 
@@ -847,6 +849,7 @@
 
         mContext = context;
         mFactoryTest = factoryTest;
+        mOnlyCore = onlyCore;
         mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings();
@@ -1051,18 +1054,20 @@
             mInstaller.moveFiles();
 
             // Prune any system packages that no longer exist.
-            Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
-            while (psit.hasNext()) {
-                PackageSetting ps = psit.next();
-                if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
-                        && !mPackages.containsKey(ps.name)
-                        && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
-                    psit.remove();
-                    String msg = "System package " + ps.name
-                            + " no longer exists; wiping its data";
-                    reportSettingsProblem(Log.WARN, msg);
-                    mInstaller.remove(ps.name, 0);
-                    mUserManager.removePackageForAllUsers(ps.name);
+            if (!mOnlyCore) {
+                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
+                while (psit.hasNext()) {
+                    PackageSetting ps = psit.next();
+                    if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
+                            && !mPackages.containsKey(ps.name)
+                            && !mSettings.mDisabledSysPackages.containsKey(ps.name)) {
+                        psit.remove();
+                        String msg = "System package " + ps.name
+                                + " no longer exists; wiping its data";
+                        reportSettingsProblem(Log.WARN, msg);
+                        mInstaller.remove(ps.name, 0);
+                        mUserManager.removePackageForAllUsers(ps.name);
+                    }
                 }
             }
             
@@ -1077,18 +1082,23 @@
             //delete tmp files
             deleteTempPackageFiles();
 
-            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
-                    SystemClock.uptimeMillis());
-            mAppInstallObserver = new AppDirObserver(
-                mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
-            mAppInstallObserver.startWatching();
-            scanDirLI(mAppInstallDir, 0, scanMode, 0);
-
-            mDrmAppInstallObserver = new AppDirObserver(
-                mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
-            mDrmAppInstallObserver.startWatching();
-            scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
-                    scanMode, 0);
+            if (!mOnlyCore) {
+                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
+                        SystemClock.uptimeMillis());
+                mAppInstallObserver = new AppDirObserver(
+                    mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
+                mAppInstallObserver.startWatching();
+                scanDirLI(mAppInstallDir, 0, scanMode, 0);
+    
+                mDrmAppInstallObserver = new AppDirObserver(
+                    mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
+                mDrmAppInstallObserver.startWatching();
+                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
+                        scanMode, 0);
+            } else {
+                mAppInstallObserver = null;
+                mDrmAppInstallObserver = null;
+            }
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                     SystemClock.uptimeMillis());
@@ -2749,6 +2759,7 @@
         parseFlags |= mDefParseFlags;
         PackageParser pp = new PackageParser(scanPath);
         pp.setSeparateProcesses(mSeparateProcesses);
+        pp.setOnlyCoreApps(mOnlyCore);
         final PackageParser.Package pkg = pp.parsePackage(scanFile,
                 scanPath, mMetrics, parseFlags);
         if (pkg == null) {
@@ -4044,7 +4055,7 @@
                         + " info=" + bp.pendingInfo);
                 if (bp.packageSetting == null && bp.pendingInfo != null) {
                     final BasePermission tree = findPermissionTreeLP(bp.name);
-                    if (tree != null) {
+                    if (tree != null && tree.perm != null) {
                         bp.packageSetting = tree.packageSetting;
                         bp.perm = new PackageParser.Permission(tree.perm.owner,
                                 new PermissionInfo(bp.pendingInfo));
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index 54bce09..1025fa8 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -35,22 +35,21 @@
 
     while ((n = q->read(buffer, 8)) > 0) {
         for (int i=0 ; i<n ; i++) {
-            if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
-                printf("time=%lld, value=<%5.1f,%5.1f,%5.1f>\n",
-                        buffer[i].timestamp,
-                        buffer[i].acceleration.x,
-                        buffer[i].acceleration.y,
-                        buffer[i].acceleration.z);
-            }
-
+            float t;
             if (oldTimeStamp) {
-                float t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
-                printf("%f ms (%f Hz)\n", t*1000, 1.0/t);
+                t = float(buffer[i].timestamp - oldTimeStamp) / s2ns(1);
             } else {
-                float t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
-                printf("first event: %f ms\n", t*1000);
+                t = float(buffer[i].timestamp - sStartTime) / s2ns(1);
             }
             oldTimeStamp = buffer[i].timestamp;
+
+            if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
+                printf("%lld\t%8f\t%8f\t%8f\t%f\n",
+                        buffer[i].timestamp,
+                        buffer[i].data[0], buffer[i].data[1], buffer[i].data[2],
+                        1.0/t);
+            }
+
         }
     }
     if (n<0 && n != -EAGAIN) {
@@ -79,7 +78,7 @@
 
     q->enableSensor(accelerometer);
 
-    q->setEventRate(accelerometer, ms2ns(200));
+    q->setEventRate(accelerometer, ms2ns(10));
 
     sp<Looper> loop = new Looper(false);
     loop->addFd(q->getFd(), 0, ALOOPER_EVENT_INPUT, receiver, q.get());
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_extended b/services/tests/servicestests/res/raw/xt_qtaguid_extended
index 5bef3dd..2f3b4ec 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_extended
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_extended
@@ -1,3 +1,3 @@
-acct_tag_hex uid_tag_int iface rx_bytes rx_packets tx_bytes tx_packets teleported_goats
-0x0 1000 test0 1024 10 2048 20 2716057
-0x0000F00D00000000 1000 test0 512 5 512 5 3370318
+acct_tag_hex uid_tag_int iface rx_bytes rx_packets tx_bytes tx_packets teleported_goats idx
+0x0 1000 test0 1024 10 2048 20 2716057 2
+0x0000F00D00000000 1000 test0 512 5 512 5 3370318 3
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical b/services/tests/servicestests/res/raw/xt_qtaguid_typical
index 7c4f04e..8df4b1b 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_typical
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_typical
@@ -1,32 +1,32 @@
 idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
-1 wlan0 0x0 0 14615 4270
-2 wlan0 0x0 1000 5175 915
-3 wlan0 0x0 1021 3381 903
-4 wlan0 0x0 10004 333821 53558
-5 wlan0 0x0 10010 4888 37363
-6 wlan0 0x0 10013 52 104
-7 wlan0 0x74182ada00000000 10004 18725 1066
-8 rmnet0 0x0 0 301274 30244
-9 rmnet0 0x0 1000 304 441
-10 rmnet0 0x0 1013 2880 2272
-11 rmnet0 0x0 1021 31407 8430
-12 rmnet0 0x0 10003 32665 3814
-13 rmnet0 0x0 10004 2373141 420112
-14 rmnet0 0x0 10010 870370 1111727
-15 rmnet0 0x0 10013 240 240
-16 rmnet0 0x0 10016 16703 13512
-17 rmnet0 0x0 10017 3990 3269
-18 rmnet0 0x0 10018 474504 14516062
-19 rmnet0 0x0 10019 782804 71077
-20 rmnet0 0x0 10022 70671 49684
-21 rmnet0 0x0 10029 5785354 397159
-22 rmnet0 0x0 10033 2102 1686
-23 rmnet0 0x0 10034 15495464 227694
-24 rmnet0 0x0 10037 31184994 684122
-25 rmnet0 0x0 10051 298687 113485
-26 rmnet0 0x0 10056 29504 20669
-27 rmnet0 0x0 10069 683 596
-28 rmnet0 0x0 10072 34051 12453
-29 rmnet0 0x0 10077 7025393 213866
-30 rmnet0 0x0 10081 354 1178
-31 rmnet0 0x74182ada00000000 10037 28507378 437004
+2 wlan0 0x0 0 14615 4270
+3 wlan0 0x0 1000 5175 915
+4 wlan0 0x0 1021 3381 903
+5 wlan0 0x0 10004 333821 53558
+6 wlan0 0x0 10010 4888 37363
+7 wlan0 0x0 10013 52 104
+8 wlan0 0x74182ada00000000 10004 18725 1066
+9 rmnet0 0x0 0 301274 30244
+10 rmnet0 0x0 1000 304 441
+11 rmnet0 0x0 1013 2880 2272
+12 rmnet0 0x0 1021 31407 8430
+13 rmnet0 0x0 10003 32665 3814
+14 rmnet0 0x0 10004 2373141 420112
+15 rmnet0 0x0 10010 870370 1111727
+16 rmnet0 0x0 10013 240 240
+17 rmnet0 0x0 10016 16703 13512
+18 rmnet0 0x0 10017 3990 3269
+19 rmnet0 0x0 10018 474504 14516062
+20 rmnet0 0x0 10019 782804 71077
+21 rmnet0 0x0 10022 70671 49684
+22 rmnet0 0x0 10029 5785354 397159
+23 rmnet0 0x0 10033 2102 1686
+24 rmnet0 0x0 10034 15495464 227694
+25 rmnet0 0x0 10037 31184994 684122
+26 rmnet0 0x0 10051 298687 113485
+27 rmnet0 0x0 10056 29504 20669
+28 rmnet0 0x0 10069 683 596
+29 rmnet0 0x0 10072 34051 12453
+30 rmnet0 0x0 10077 7025393 213866
+31 rmnet0 0x0 10081 354 1178
+32 rmnet0 0x74182ada00000000 10037 28507378 437004
diff --git a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set b/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
index 3678b10..f9f34ac 100644
--- a/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
+++ b/services/tests/servicestests/res/raw/xt_qtaguid_typical_with_set
@@ -1,13 +1,13 @@
 idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_packets rx_tcp_bytes rx_udp_packets rx_udp_bytes rx_other_packets rx_other_bytes tx_tcp_packets tx_tcp_bytes tx_udp_packets tx_udp_bytes tx_other_packets tx_other_bytes

-1 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0

-1 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-2 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0

-2 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0

-3 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0

-3 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-4 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0

-4 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-5 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0

-5 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

-6 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0

-6 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+2 rmnet0 0x0 0 0 14855 82 2804 47 2000 45 12799 35 56 2 676 13 2128 34 0 0

+3 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+4 rmnet0 0x0 1000 0 278102 253 10487 182 277342 243 760 10 0 0 9727 172 760 10 0 0

+5 rmnet0 0x0 1000 1 26033 30 1401 26 25881 28 152 2 0 0 1249 24 152 2 0 0

+6 rmnet0 0x0 10012 0 40524 272 134138 293 40524 272 0 0 0 0 134138 293 0 0 0 0

+7 rmnet0 0x0 10012 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+8 rmnet0 0x0 10034 0 15791 59 9905 69 15791 59 0 0 0 0 9905 69 0 0 0 0

+9 rmnet0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+10 rmnet0 0x0 10055 0 3602 29 7739 59 3602 29 0 0 0 0 7739 59 0 0 0 0

+11 rmnet0 0x0 10055 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

+12 rmnet0 0x7fff000300000000 1000 0 483 4 1931 6 483 4 0 0 0 0 1931 6 0 0 0 0

+13 rmnet0 0x7fff000300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index c553947..f417ddd 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -442,6 +442,7 @@
 
             if (wasConnected) {
                 mLocalIp = null;
+                stopPortMappingMeasurement();
                 for (SipSessionGroupExt group : mSipGroups.values()) {
                     group.onConnectivityChanged(false);
                 }
@@ -457,7 +458,6 @@
                 if (isWifi && (mWifiLock != null)) stopWifiScanner();
             } else {
                 mMyWakeLock.reset(); // in case there's a leak
-                stopPortMappingMeasurement();
                 if (isWifi && (mWifiLock != null)) startWifiScanner();
             }
         } catch (SipException e) {
@@ -784,52 +784,50 @@
         private static final int PASS_THRESHOLD = 10;
         private static final int MAX_RETRY_COUNT = 5;
         private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
+        private SipProfile mLocalProfile;
         private SipSessionGroupExt mGroup;
         private SipSessionGroup.SipSessionImpl mSession;
         private int mMinInterval;
         private int mMaxInterval;
         private int mInterval;
-        private int mPassCount = 0;
+        private int mPassCount;
 
         public IntervalMeasurementProcess(SipProfile localProfile,
                 int minInterval, int maxInterval) {
             mMaxInterval = maxInterval;
             mMinInterval = minInterval;
-            mInterval = (maxInterval + minInterval) / 2;
-
-            // Don't start measurement if the interval is too small
-            if (mInterval < DEFAULT_KEEPALIVE_INTERVAL) {
-                Log.w(TAG, "interval is too small; measurement aborted; "
-                        + "maxInterval=" + mMaxInterval);
-                return;
-            } else if (checkTermination()) {
-                Log.w(TAG, "interval is too small; measurement aborted; "
-                        + "interval=[" + mMinInterval + "," + mMaxInterval
-                        + "]");
-                return;
-            }
-
-            try {
-                mGroup =  new SipSessionGroupExt(localProfile, null, null);
-                // TODO: remove this line once SipWakeupTimer can better handle
-                // variety of timeout values
-                mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
-            } catch (Exception e) {
-                Log.w(TAG, "start interval measurement error: " + e);
-            }
+            mLocalProfile = localProfile;
         }
 
         public void start() {
             synchronized (SipService.this) {
-                Log.d(TAG, "start measurement w interval=" + mInterval);
-                if (mSession == null) {
+                if (mSession != null) {
+                    return;
+                }
+
+                mInterval = (mMaxInterval + mMinInterval) / 2;
+                mPassCount = 0;
+
+                // Don't start measurement if the interval is too small
+                if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) {
+                    Log.w(TAG, "measurement aborted; interval=[" +
+                            mMinInterval + "," + mMaxInterval + "]");
+                    return;
+                }
+
+                try {
+                    Log.d(TAG, "start measurement w interval=" + mInterval);
+
+                    mGroup = new SipSessionGroupExt(mLocalProfile, null, null);
+                    // TODO: remove this line once SipWakeupTimer can better handle
+                    // variety of timeout values
+                    mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
+
                     mSession = (SipSessionGroup.SipSessionImpl)
                             mGroup.createSession(null);
-                }
-                try {
                     mSession.startKeepAliveProcess(mInterval, this);
-                } catch (SipException e) {
-                    Log.e(TAG, "start()", e);
+                } catch (Throwable t) {
+                    onError(SipErrorCode.CLIENT_ERROR, t.toString());
                 }
             }
         }
@@ -840,6 +838,10 @@
                     mSession.stopKeepAliveProcess();
                     mSession = null;
                 }
+                if (mGroup != null) {
+                    mGroup.close();
+                    mGroup = null;
+                }
                 mTimer.cancel(this);
             }
         }
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index eb5cce7..06cdaf2 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -100,7 +100,7 @@
     private static final int EXPIRY_TIME = 3600; // in seconds
     private static final int CANCEL_CALL_TIMER = 3; // in seconds
     private static final int END_CALL_TIMER = 3; // in seconds
-    private static final int KEEPALIVE_TIMEOUT = 3; // in seconds
+    private static final int KEEPALIVE_TIMEOUT = 5; // in seconds
     private static final int INCALL_KEEPALIVE_INTERVAL = 10; // in seconds
     private static final long WAKE_LOCK_HOLDING_TIME = 500; // in milliseconds
 
@@ -1555,7 +1555,7 @@
                     try {
                         sendKeepAlive();
                     } catch (Throwable t) {
-                        Log.w(TAG, "keepalive error: " + ": "
+                        Log.w(TAG, "keepalive error: "
                                 + mLocalProfile.getUriString(), getRootCause(t));
                         // It's possible that the keepalive process is being stopped
                         // during session.sendKeepAlive() so need to check mRunning