Merge "Fix bug 5226097 - App compatibility issues around new ListView fixes"
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/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..1379dd2d 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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fb3f6e8..81f9d78 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -164,11 +164,14 @@
 
     final W mWindow;
 
+    final int mTargetSdkVersion;
+
     View mView;
     View mFocusedView;
     View mRealFocusedView;  // this is not set to null in touch mode
     int mViewVisibility;
     boolean mAppVisible = true;
+    int mOrigWindowType = -1;
 
     // Set to true if the owner of this window is in the stopped state,
     // so the window should no longer be active.
@@ -331,6 +334,7 @@
         mVisRect = new Rect();
         mWinFrame = new Rect();
         mWindow = new W(this);
+        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
         mInputMethodCallback = new InputMethodCallback(this);
         mViewVisibility = View.GONE;
         mTransparentRegion = new Region();
@@ -461,6 +465,7 @@
                     mInputChannel = new InputChannel();
                 }
                 try {
+                    mOrigWindowType = mWindowAttributes.type;
                     res = sWindowSession.add(mWindow, mWindowAttributes,
                             getHostVisibility(), mAttachInfo.mContentInsets,
                             mInputChannel);
@@ -3481,6 +3486,14 @@
         }
         mPendingConfiguration.seq = 0;
         //Log.d(TAG, ">>>>>> CALLING relayout");
+        if (params != null && mOrigWindowType != params.type) {
+            // For compatibility with old apps, don't crash here.
+            if (mTargetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                Slog.w(TAG, "Window type can not be changed after "
+                        + "the window is added; ignoring change of " + mView);
+                params.type = mOrigWindowType;
+            }
+        }
         int relayoutResult = sWindowSession.relayout(
                 mWindow, params,
                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 70d2bd7..ecd99b2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9560,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) {
@@ -9585,6 +9588,8 @@
 
         public SuggestionsPopupWindow() {
             mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+            mSuggestionSpanComparator = new SuggestionSpanComparator();
+            mSpansLengths = new HashMap<SuggestionSpan, Integer>();
         }
 
         @Override
@@ -9663,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.
@@ -9672,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/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/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/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 670ee54..298536b4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -25,4 +25,7 @@
     <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/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b153613..0b65d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1845,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/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 94efa74..a58f64c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -87,6 +87,8 @@
 // RecordThread loop sleep time upon application overrun or audio HAL read error
 static const int kRecordThreadSleepUs = 5000;
 
+static const nsecs_t kSetParametersTimeout = seconds(2);
+
 // ----------------------------------------------------------------------------
 
 static bool recordingAllowed() {
@@ -1032,7 +1034,7 @@
     mWaitWorkCV.signal();
     // wait condition with timeout in case the thread loop has exited
     // before the request could be processed
-    if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) {
+    if (mParamCond.waitRelative(mLock, kSetParametersTimeout) == NO_ERROR) {
         status = mParamStatus;
         mWaitWorkCV.signal();
     } else {
@@ -2349,7 +2351,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -2828,7 +2832,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -4669,7 +4675,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }