Merge "Fix issue #6686339: 2 taps required to launch notification..." into jb-dev
diff --git a/Android.mk b/Android.mk
index 5aaea97..79e3140 100644
--- a/Android.mk
+++ b/Android.mk
@@ -193,11 +193,12 @@
 	location/java/android/location/INetInitiatedListener.aidl \
 	media/java/android/media/IAudioService.aidl \
 	media/java/android/media/IAudioFocusDispatcher.aidl \
-    media/java/android/media/IAudioRoutesObserver.aidl \
+	media/java/android/media/IAudioRoutesObserver.aidl \
 	media/java/android/media/IMediaScannerListener.aidl \
 	media/java/android/media/IMediaScannerService.aidl \
 	media/java/android/media/IRemoteControlClient.aidl \
 	media/java/android/media/IRemoteControlDisplay.aidl \
+	media/java/android/media/IRemoteVolumeObserver.aidl \
 	media/java/android/media/IRingtonePlayer.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index 4a23046..6072ad9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -676,6 +676,7 @@
     field public static final int measureAllChildren = 16843018; // 0x101010a
     field public static final int measureWithLargestChild = 16843476; // 0x10102d4
     field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad
+    field public static final int mediaRouteTypes = 16843694; // 0x10103ae
     field public static final int menuCategory = 16843230; // 0x10101de
     field public static final int mimeType = 16842790; // 0x1010026
     field public static final int minDate = 16843583; // 0x101033f
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 4d3a519..d8f9e49 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -942,8 +942,10 @@
 
             @Override
             public void onAnimationStart(Animator animator) {
-                if (mListeners != null) {
-                    for (TransitionListener listener : mListeners) {
+                if (hasListeners()) {
+                    ArrayList<TransitionListener> listeners =
+                            (ArrayList<TransitionListener>) mListeners.clone();
+                    for (TransitionListener listener : listeners) {
                         listener.startTransition(LayoutTransition.this, parent, child,
                                 changeReason == APPEARING ?
                                         CHANGE_APPEARING : changeReason == DISAPPEARING ?
@@ -961,8 +963,10 @@
             @Override
             public void onAnimationEnd(Animator animator) {
                 currentChangingAnimations.remove(child);
-                if (mListeners != null) {
-                    for (TransitionListener listener : mListeners) {
+                if (hasListeners()) {
+                    ArrayList<TransitionListener> listeners =
+                            (ArrayList<TransitionListener>) mListeners.clone();
+                    for (TransitionListener listener : listeners) {
                         listener.endTransition(LayoutTransition.this, parent, child,
                                 changeReason == APPEARING ?
                                         CHANGE_APPEARING : changeReason == DISAPPEARING ?
@@ -1131,8 +1135,10 @@
             currentAnimation.cancel();
         }
         if (mAppearingAnim == null) {
-            if (mListeners != null) {
-                for (TransitionListener listener : mListeners) {
+            if (hasListeners()) {
+                ArrayList<TransitionListener> listeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                for (TransitionListener listener : listeners) {
                     listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
                 }
             }
@@ -1149,8 +1155,10 @@
             @Override
             public void onAnimationEnd(Animator anim) {
                 currentAppearingAnimations.remove(child);
-                if (mListeners != null) {
-                    for (TransitionListener listener : mListeners) {
+                if (hasListeners()) {
+                    ArrayList<TransitionListener> listeners =
+                            (ArrayList<TransitionListener>) mListeners.clone();
+                    for (TransitionListener listener : listeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
                     }
                 }
@@ -1172,8 +1180,10 @@
             currentAnimation.cancel();
         }
         if (mDisappearingAnim == null) {
-            if (mListeners != null) {
-                for (TransitionListener listener : mListeners) {
+            if (hasListeners()) {
+                ArrayList<TransitionListener> listeners =
+                        (ArrayList<TransitionListener>) mListeners.clone();
+                for (TransitionListener listener : listeners) {
                     listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
                 }
             }
@@ -1189,8 +1199,10 @@
             public void onAnimationEnd(Animator anim) {
                 currentDisappearingAnimations.remove(child);
                 child.setAlpha(preAnimAlpha);
-                if (mListeners != null) {
-                    for (TransitionListener listener : mListeners) {
+                if (hasListeners()) {
+                    ArrayList<TransitionListener> listeners =
+                            (ArrayList<TransitionListener>) mListeners.clone();
+                    for (TransitionListener listener : listeners) {
                         listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
                     }
                 }
@@ -1228,8 +1240,10 @@
             cancel(CHANGE_APPEARING);
             cancel(CHANGING);
         }
-        if (mListeners != null && (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
-            for (TransitionListener listener : mListeners) {
+        if (hasListeners() && (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
+            ArrayList<TransitionListener> listeners =
+                    (ArrayList<TransitionListener>) mListeners.clone();
+            for (TransitionListener listener : listeners) {
                 listener.startTransition(this, parent, child, APPEARING);
             }
         }
@@ -1241,6 +1255,10 @@
         }
     }
 
+    private boolean hasListeners() {
+        return mListeners != null && mListeners.size() > 0;
+    }
+
     /**
      * This method is called by ViewGroup when there is a call to layout() on the container
      * with this LayoutTransition. If the CHANGING transition is enabled and if there is no other
@@ -1328,8 +1346,10 @@
             cancel(CHANGE_DISAPPEARING);
             cancel(CHANGING);
         }
-        if (mListeners != null && (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
-            for (TransitionListener listener : mListeners) {
+        if (hasListeners() && (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
+            ArrayList<TransitionListener> listeners = (ArrayList<TransitionListener>) mListeners
+                    .clone();
+            for (TransitionListener listener : listeners) {
                 listener.startTransition(this, parent, child, DISAPPEARING);
             }
         }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 9ba5305..39e2423 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1118,7 +1118,9 @@
         if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
         final boolean inactive = !fragment.isInBackStack();
         if (!fragment.mDetached || inactive) {
-            mAdded.remove(fragment);
+            if (mAdded != null) {
+                mAdded.remove(fragment);
+            }
             if (fragment.mHasMenu && fragment.mMenuVisible) {
                 mNeedMenuInvalidate = true;
             }
@@ -1187,7 +1189,9 @@
             fragment.mDetached = true;
             if (fragment.mAdded) {
                 // We are not already in back stack, so need to remove the fragment.
-                mAdded.remove(fragment);
+                if (mAdded != null) {
+                    mAdded.remove(fragment);
+                }
                 if (fragment.mHasMenu && fragment.mMenuVisible) {
                     mNeedMenuInvalidate = true;
                 }
@@ -1202,6 +1206,9 @@
         if (fragment.mDetached) {
             fragment.mDetached = false;
             if (!fragment.mAdded) {
+                if (mAdded == null) {
+                    mAdded = new ArrayList<Fragment>();
+                }
                 mAdded.add(fragment);
                 fragment.mAdded = true;
                 if (fragment.mHasMenu && fragment.mMenuVisible) {
@@ -1213,7 +1220,7 @@
     }
 
     public Fragment findFragmentById(int id) {
-        if (mActive != null) {
+        if (mAdded != null) {
             // First look through added fragments.
             for (int i=mAdded.size()-1; i>=0; i--) {
                 Fragment f = mAdded.get(i);
@@ -1221,6 +1228,8 @@
                     return f;
                 }
             }
+        }
+        if (mActive != null) {
             // Now for any known fragment.
             for (int i=mActive.size()-1; i>=0; i--) {
                 Fragment f = mActive.get(i);
@@ -1233,7 +1242,7 @@
     }
     
     public Fragment findFragmentByTag(String tag) {
-        if (mActive != null && tag != null) {
+        if (mAdded != null && tag != null) {
             // First look through added fragments.
             for (int i=mAdded.size()-1; i>=0; i--) {
                 Fragment f = mAdded.get(i);
@@ -1241,6 +1250,8 @@
                     return f;
                 }
             }
+        }
+        if (mActive != null && tag != null) {
             // Now for any known fragment.
             for (int i=mActive.size()-1; i>=0; i--) {
                 Fragment f = mActive.get(i);
@@ -1817,7 +1828,7 @@
     }
     
     public void dispatchConfigurationChanged(Configuration newConfig) {
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null) {
@@ -1828,7 +1839,7 @@
     }
 
     public void dispatchLowMemory() {
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null) {
@@ -1839,7 +1850,7 @@
     }
 
     public void dispatchTrimMemory(int level) {
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null) {
@@ -1852,7 +1863,7 @@
     public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         boolean show = false;
         ArrayList<Fragment> newMenus = null;
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
@@ -1882,7 +1893,7 @@
     
     public boolean dispatchPrepareOptionsMenu(Menu menu) {
         boolean show = false;
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
@@ -1895,7 +1906,7 @@
     }
     
     public boolean dispatchOptionsItemSelected(MenuItem item) {
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
@@ -1909,7 +1920,7 @@
     }
     
     public boolean dispatchContextItemSelected(MenuItem item) {
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null && !f.mHidden && f.mUserVisibleHint) {
@@ -1923,7 +1934,7 @@
     }
     
     public void dispatchOptionsMenuClosed(Menu menu) {
-        if (mActive != null) {
+        if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index 018b25d..18713f5 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -73,9 +73,14 @@
                 com.android.internal.R.styleable.MediaRouteButton_minWidth, 0);
         mMinHeight = a.getDimensionPixelSize(
                 com.android.internal.R.styleable.MediaRouteButton_minHeight, 0);
+        final int routeTypes = a.getInteger(
+                com.android.internal.R.styleable.MediaRouteButton_mediaRouteTypes,
+                MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
         a.recycle();
 
         setClickable(true);
+
+        setRouteTypes(routeTypes);
     }
 
     private void setRemoteIndicatorDrawable(Drawable d) {
@@ -110,7 +115,7 @@
                     final RouteInfo route = mRouter.getRouteAt(i);
                     if ((route.getSupportedTypes() & mRouteTypes) != 0 &&
                             route != mRouter.getSystemAudioRoute()) {
-                        mRouter.selectRoute(mRouteTypes, route);
+                        mRouter.selectRouteInt(mRouteTypes, route);
                     }
                 }
             }
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index e8bd546..d1d5131 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -840,29 +840,17 @@
     }
 
     /**
-     * Returns true if the global assist activity is available.
-     * @return True if the assistant is available.
-     *
-     * @hide
-     */
-    public final boolean isAssistantAvailable() {
-        Intent intent = getAssistIntent();
-        return intent != null
-                && mContext.getPackageManager().queryIntentActivities(intent,
-                        PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
-    }
-
-    /**
-     * Gets an intent to launch the global assist activity, or null if not available.
+     * Gets an intent for launching installed assistant activity, or null if not available.
      * @return The assist intent.
      *
      * @hide
      */
-    public final Intent getAssistIntent() {
-        ComponentName globalSearchActivity = getGlobalSearchActivity();
-        if (globalSearchActivity != null) {
-            Intent intent = new Intent(Intent.ACTION_ASSIST);
-            intent.setPackage(globalSearchActivity.getPackageName());
+    public static final Intent getAssistIntent(Context context) {
+        PackageManager pm = context.getPackageManager();
+        Intent intent = new Intent(Intent.ACTION_ASSIST);
+        ComponentName component = intent.resolveActivity(pm);
+        if (component != null) {
+            intent.setComponent(component);
             return intent;
         }
         return null;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 50972e8..76dfac4 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2153,19 +2153,6 @@
             "android.intent.action.USB_AUDIO_DEVICE_PLUG";
 
     /**
-     * @hide (to be un-hidden)
-     * Broadcast Action: the volume handled by the receiver should be updated based on the
-     * mutually exclusive extras, {@link #EXTRA_VOLUME_UPDATE_DIRECTION}
-     * and {@link #EXTRA_VOLUME_UPDATE_VALUE}.
-     *
-     * @see #EXTRA_VOLUME_UPDATE_DIRECTION
-     * @see #EXTRA_VOLUME_UPDATE_VALUE
-     * @see android.media.RemoteControlClient
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_VOLUME_UPDATE = "android.intent.action.VOLUME_UPDATE";
-
-    /**
      * <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p>
      * <ul>
      *   <li><em>state</em> - A boolean value indicating whether the settings is on or off.</li>
@@ -2854,26 +2841,6 @@
     public static final String EXTRA_USERID =
             "android.intent.extra.user_id";
 
-    /**
-     * @hide (to be un-hidden)
-     * An integer indicating whether the volume is to be increased (positive value) or decreased
-     * (negative value). For bundled changes, the absolute value indicates the number of changes
-     * in the same direction, e.g. +3 corresponds to three "volume up" changes.
-     * @see #ACTION_VOLUME_UPDATE
-     */
-    public static final String EXTRA_VOLUME_UPDATE_DIRECTION =
-            "android.intent.extra.VOLUME_UPDATE_DIRECTION";
-
-    /**
-     * @hide (to be un-hidden)
-     * An integer indicating the new volume value, always between 0 and the value set for
-     * {@link RemoteControlClient#PLAYBACKINFO_VOLUME_MAX} with
-     * {@link RemoteControlClient#setPlaybackInformation(int, int)}
-     * @see #ACTION_VOLUME_UPDATE
-     */
-    public static final String EXTRA_VOLUME_UPDATE_VALUE =
-            "android.intent.extra.VOLUME_UPDATE_VALUE";
-
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index cb5a5e7..dab48b1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -27,6 +27,7 @@
 import android.os.Looper;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.util.Log;
 import com.google.android.gles_jni.EGLImpl;
 
@@ -40,6 +41,7 @@
 
 import java.io.File;
 import java.io.PrintWriter;
+import java.util.concurrent.locks.ReentrantLock;
 
 import static javax.microedition.khronos.egl.EGL10.*;
 
@@ -623,6 +625,7 @@
 
         final boolean mProfileEnabled;
         final float[] mProfileData;
+        final ReentrantLock mProfileLock;
         int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
         
         final boolean mDebugDirtyRegions;
@@ -663,8 +666,11 @@
                 for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
                     mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
                 }
+
+                mProfileLock = new ReentrantLock();
             } else {
                 mProfileData = null;
+                mProfileLock = null;
             }
 
             property = SystemProperties.get(DEBUG_DIRTY_REGIONS_PROPERTY, "false");
@@ -678,15 +684,21 @@
         void dumpGfxInfo(PrintWriter pw) {
             if (mProfileEnabled) {
                 pw.printf("\n\tDraw\tProcess\tExecute\n");
-                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                    if (mProfileData[i] < 0) {
-                        break;
+
+                mProfileLock.lock();
+                try {
+                    for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+                        if (mProfileData[i] < 0) {
+                            break;
+                        }
+                        pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
+                                mProfileData[i + 2]);
+                        mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
                     }
-                    pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
-                            mProfileData[i + 2]);
-                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
+                    mProfileCurrentFrame = mProfileData.length;
+                } finally {
+                    mProfileLock.unlock();
                 }
-                mProfileCurrentFrame = mProfileData.length;
             }
         }
 
@@ -1083,7 +1095,11 @@
                 if (surfaceState != SURFACE_STATE_ERROR) {
                     HardwareCanvas canvas = mCanvas;
                     attachInfo.mHardwareCanvas = canvas;
-                    
+
+                    if (mProfileEnabled) {
+                        mProfileLock.lock();
+                    }
+
                     // We had to change the current surface and/or context, redraw everything
                     if (surfaceState == SURFACE_STATE_UPDATED) {
                         dirty = null;
@@ -1121,7 +1137,14 @@
                             getDisplayListStartTime = System.nanoTime();
                         }
 
-                        DisplayList displayList = view.getDisplayList();
+                        DisplayList displayList;
+
+                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+                        try {
+                            displayList = view.getDisplayList();
+                        } finally {
+                            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+                        }
 
                         if (mProfileEnabled) {
                             long now = System.nanoTime();
@@ -1136,8 +1159,13 @@
                                 drawDisplayListStartTime = System.nanoTime();
                             }
 
-                            status |= canvas.drawDisplayList(displayList, mRedrawClip,
-                                    DisplayList.FLAG_CLIP_CHILDREN);
+                            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
+                            try {
+                                status |= canvas.drawDisplayList(displayList, mRedrawClip,
+                                        DisplayList.FLAG_CLIP_CHILDREN);
+                            } finally {
+                                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+                            }
 
                             if (mProfileEnabled) {
                                 long now = System.nanoTime();
@@ -1174,7 +1202,6 @@
                     attachInfo.mIgnoreDirtyState = false;
                     
                     if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
-
                         long eglSwapBuffersStartTime = 0;
                         if (mProfileEnabled) {
                             eglSwapBuffersStartTime = System.nanoTime();
@@ -1191,6 +1218,10 @@
                         checkEglErrors();
                     }
 
+                    if (mProfileEnabled) {
+                        mProfileLock.unlock();
+                    }
+
                     return dirty == null;
                 }
             }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e7b0e78..044627c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -997,13 +997,13 @@
                 mTransition.showChild(this, child, oldVisibility);
             } else {
                 mTransition.hideChild(this, child, newVisibility);
-                // Only track this on disappearing views - appearing views are already visible
-                // and don't need special handling during drawChild()
-                if (mVisibilityChangingChildren == null) {
-                    mVisibilityChangingChildren = new ArrayList<View>();
-                }
-                mVisibilityChangingChildren.add(child);
                 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
+                    // Only track this on disappearing views - appearing views are already visible
+                    // and don't need special handling during drawChild()
+                    if (mVisibilityChangingChildren == null) {
+                        mVisibilityChangingChildren = new ArrayList<View>();
+                    }
+                    mVisibilityChangingChildren.add(child);
                     addDisappearingView(child);
                 }
             }
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
index adea586..62410ed 100644
--- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
@@ -29,7 +29,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Vibrator;
@@ -361,7 +360,6 @@
                 mHandleDrawable.setAlpha(0.0f);
                 deactivateTargets();
                 showTargets(true);
-                ping();
                 startBackgroundAnimation(INITIAL_SHOW_HANDLE_DURATION, 1.0f);
                 setGrabbedState(OnTriggerListener.CENTER_HANDLE);
                 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
@@ -485,11 +483,7 @@
         final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
         final int delay = animate ? HIDE_ANIMATION_DELAY : 0;
 
-        // TODO: add an attribute for this. For now we'll show the expand for navbar, but not
-        // keyguard.
-        final boolean expandDisabled = !mAlwaysTrackFinger;
-
-        final float targetScale = (expanded || expandDisabled) ?
+        final float targetScale = expanded ?
                 TARGET_SCALE_EXPANDED : TARGET_SCALE_COLLAPSED;
         final int length = mTargetDrawables.size();
         final TimeInterpolator interpolator = Ease.Cubic.easeOut;
@@ -505,7 +499,7 @@
                     "onUpdate", mUpdateListener));
         }
 
-        final float ringScaleTarget = (expanded || expandDisabled) ?
+        final float ringScaleTarget = expanded ?
                 RING_SCALE_EXPANDED : RING_SCALE_COLLAPSED;
         mTargetAnimations.add(Tweener.to(mOuterRing, duration,
                 "ease", interpolator,
@@ -1209,25 +1203,32 @@
                 int existingResId) {
         if (existingResId == 0) return false;
 
-        try {
-            PackageManager packageManager = mContext.getPackageManager();
-            // Look for the search icon specified in the activity meta-data
-            Bundle metaData = packageManager.getActivityInfo(
-                    component, PackageManager.GET_META_DATA).metaData;
-            if (metaData != null) {
-                int iconResId = metaData.getInt(name);
-                if (iconResId != 0) {
-                    Resources res = packageManager.getResourcesForActivity(component);
-                    return replaceTargetDrawables(res, existingResId, iconResId);
+        boolean replaced = false;
+        if (component != null) {
+            try {
+                PackageManager packageManager = mContext.getPackageManager();
+                // Look for the search icon specified in the activity meta-data
+                Bundle metaData = packageManager.getActivityInfo(
+                        component, PackageManager.GET_META_DATA).metaData;
+                if (metaData != null) {
+                    int iconResId = metaData.getInt(name);
+                    if (iconResId != 0) {
+                        Resources res = packageManager.getResourcesForActivity(component);
+                        replaced = replaceTargetDrawables(res, existingResId, iconResId);
+                    }
                 }
+            } catch (NameNotFoundException e) {
+                Log.w(TAG, "Failed to swap drawable; "
+                        + component.flattenToShortString() + " not found", e);
+            } catch (Resources.NotFoundException nfe) {
+                Log.w(TAG, "Failed to swap drawable from "
+                        + component.flattenToShortString(), nfe);
             }
-        } catch (NameNotFoundException e) {
-            Log.w(TAG, "Failed to swap drawable; "
-                    + component.flattenToShortString() + " not found", e);
-        } catch (Resources.NotFoundException nfe) {
-            Log.w(TAG, "Failed to swap drawable from "
-                    + component.flattenToShortString(), nfe);
         }
-        return false;
+        if (!replaced) {
+            // Restore the original drawable
+            replaceTargetDrawables(mContext.getResources(), existingResId, existingResId);
+        }
+        return replaced;
     }
 }
diff --git a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java
index 1a5a9a2..bbd1276 100644
--- a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java
+++ b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java
@@ -202,25 +202,25 @@
 
     public void draw(Canvas canvas) {
         ArrayList<Point> points = mPointCloud;
-        final float cx = mDrawable != null ? (-mDrawable.getIntrinsicWidth() / 2) : 0;
-        final float cy = mDrawable != null ? (-mDrawable.getIntrinsicHeight() / 2) : 0;
         canvas.save(Canvas.MATRIX_SAVE_FLAG);
         canvas.scale(mScale, mScale, mCenterX, mCenterY);
         for (int i = 0; i < points.size(); i++) {
             Point point = points.get(i);
             final float pointSize = interp(MAX_POINT_SIZE, MIN_POINT_SIZE,
                     point.radius / mOuterRadius);
-            final float px = point.x + cx + mCenterX;
-            final float py = point.y + cy + mCenterY;
+            final float px = point.x + mCenterX;
+            final float py = point.y + mCenterY;
             int alpha = getAlphaForPoint(point);
 
             if (alpha == 0) continue;
 
             if (mDrawable != null) {
                 canvas.save(Canvas.MATRIX_SAVE_FLAG);
-                float s = pointSize / MAX_POINT_SIZE;
+                final float cx = mDrawable.getIntrinsicWidth() * 0.5f;
+                final float cy = mDrawable.getIntrinsicHeight() * 0.5f;
+                final float s = pointSize / MAX_POINT_SIZE;
                 canvas.scale(s, s, px, py);
-                canvas.translate(px, py);
+                canvas.translate(px - cx, py - cy);
                 mDrawable.setAlpha(alpha);
                 mDrawable.draw(canvas);
                 canvas.restore();
diff --git a/core/res/res/drawable-hdpi/ic_find_next_holo_light.png b/core/res/res/drawable-hdpi/ic_find_next_holo_light.png
new file mode 100644
index 0000000..3748169
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_find_next_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_find_previous_holo_light.png b/core/res/res/drawable-hdpi/ic_find_previous_holo_light.png
new file mode 100644
index 0000000..e4834a2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_find_previous_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_find_next_holo_light.png b/core/res/res/drawable-mdpi/ic_find_next_holo_light.png
new file mode 100644
index 0000000..4eea3c3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_find_next_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_find_previous_holo_light.png b/core/res/res/drawable-mdpi/ic_find_previous_holo_light.png
new file mode 100644
index 0000000..786e1d6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_find_previous_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_find_next_holo_light.png b/core/res/res/drawable-xhdpi/ic_find_next_holo_light.png
new file mode 100644
index 0000000..5b6890d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_find_next_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_find_previous_holo_light.png b/core/res/res/drawable-xhdpi/ic_find_previous_holo_light.png
new file mode 100644
index 0000000..73976c7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_find_previous_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable/ic_lockscreen_outerring.xml b/core/res/res/drawable/ic_lockscreen_outerring.xml
index 3886bb4..75bea70 100644
--- a/core/res/res/drawable/ic_lockscreen_outerring.xml
+++ b/core/res/res/drawable/ic_lockscreen_outerring.xml
@@ -20,5 +20,5 @@
     <size android:height="@dimen/keyguard_lockscreen_outerring_diameter"
           android:width="@dimen/keyguard_lockscreen_outerring_diameter" />
     <solid android:color="#00000000" />
-    <stroke android:color="#00000000" android:width="2dp" />
+    <stroke android:color="#1affffff" android:width="2dp" />
 </shape>
diff --git a/core/res/res/menu/webview_find.xml b/core/res/res/menu/webview_find.xml
index 526b346..1770bd9 100644
--- a/core/res/res/menu/webview_find.xml
+++ b/core/res/res/menu/webview_find.xml
@@ -16,11 +16,11 @@
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@+id/find_prev"
-        android:icon="@drawable/ic_find_previous_holo_dark"
+        android:icon="?android:attr/findOnPagePreviousDrawable"
         android:showAsAction="always"
         />
     <item android:id="@+id/find_next"
-        android:icon="@drawable/ic_find_next_holo_dark"
+        android:icon="?android:attr/findOnPageNextDrawable"
         android:showAsAction="always"
         />
 </menu>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 3d63e84..7002578 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -934,10 +934,8 @@
     <string name="deleteText" msgid="7070985395199629156">"vee uit"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Invoermetode"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Teksaksies"</string>
-    <!-- no translation found for low_internal_storage_view_title (5576272496365684834) -->
-    <skip />
-    <!-- no translation found for low_internal_storage_view_text (6640505817617414371) -->
-    <skip />
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Bergingspasie word min"</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Sommige stelselfunksies werk moontlik nie"</string>
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1291,6 +1289,5 @@
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-klank"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Stelsel"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
-    <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) -->
-    <skip />
+    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 8e01697..ec18743 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Дынамікі станцыi"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-аўдыёвыхад"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Сістэма"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Гатова"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 902cee5..a123a48 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Докинг станц.: Високогов."</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI аудио"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4697a2d..6320ec1 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Zvuk HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 25cba5f..63456c0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockstationens højttalere"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-lyd"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Udfør"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 76a7dfd..9971e8d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index b0dd12f..59e34f0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Altavoces del conector"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fin"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index b633542..d9df2a2 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -934,10 +934,8 @@
     <string name="deleteText" msgid="7070985395199629156">"حذف"</string>
     <string name="inputMethod" msgid="1653630062304567879">"روش ورودی"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"عملکردهای متنی"</string>
-    <!-- no translation found for low_internal_storage_view_title (5576272496365684834) -->
-    <skip />
-    <!-- no translation found for low_internal_storage_view_text (6640505817617414371) -->
-    <skip />
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"فضای ذخیره‌سازی رو به اتمام است"</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"برخی از عملکردهای سیستم ممکن است کار نکنند"</string>
     <string name="ok" msgid="5970060430562524910">"تأیید"</string>
     <string name="cancel" msgid="6442560571259935130">"لغو"</string>
     <string name="yes" msgid="5362982303337969312">"تأیید"</string>
@@ -1290,8 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"بلندگوهای جایگاه اتصال"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"صدای HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
-    <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوث‌های صوتی"</string>
+    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5b13636..4a7a9c7 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Haut-parleurs de la station d\'accueil"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5128132..56a29bf 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"डॉक स्‍पीकर"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI ऑडियो"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्‍टम"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 967e3e1..80dc095 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvučnici postolja"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI audio"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sustav"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a6ab456..dad7dc6 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dokkolóegység hangszórója"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI audió"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Rendszer"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f58fe5d..303db08 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ホルダーのスピーカー"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMIオーディオ"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index b1dd2d9..ffd8c03 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"도크 스피커"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI 오디오"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 426da6b..e861fdd6 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Pembesar suara dok"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Audio HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d840532..ac6ec6c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockluidsprekers"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-audio"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systeem"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gereed"</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index a2afc72..ff66810 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -934,10 +934,8 @@
     <string name="deleteText" msgid="7070985395199629156">"ştergeţi"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Metodă de intrare"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Acţiuni pentru text"</string>
-    <!-- no translation found for low_internal_storage_view_title (5576272496365684834) -->
-    <skip />
-    <!-- no translation found for low_internal_storage_view_text (6640505817617414371) -->
-    <skip />
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Spaţiul de stocare aproape ocupat"</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Este posibil ca unele funcţii de sistem să nu funcţioneze"</string>
     <string name="ok" msgid="5970060430562524910">"OK"</string>
     <string name="cancel" msgid="6442560571259935130">"Anulaţi"</string>
     <string name="yes" msgid="5362982303337969312">"OK"</string>
@@ -1290,8 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Ieşire audio HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
-    <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
+    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ed8cd7f..b238e16 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Динамики док-станции"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-аудио"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index dc240b4..86fc758 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Reproduktory doku"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Zvuk HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4d543c7..a7aca87 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvočniki stojala"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Zvok HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Končano"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index dfe26b5..c0e9a62 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Звучници базне станице"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI аудио"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f94fe3f..4e10801 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockningsstationens högtalare"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI-ljud"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klar"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cf0f69f..5701a00 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -934,10 +934,8 @@
     <string name="deleteText" msgid="7070985395199629156">"futa"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Mbinu ya uingizaji"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Vitendo vya maandishi"</string>
-    <!-- no translation found for low_internal_storage_view_title (5576272496365684834) -->
-    <skip />
-    <!-- no translation found for low_internal_storage_view_text (6640505817617414371) -->
-    <skip />
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Nafasi ya kuhafadhi inakwisha"</string>
+    <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Baadhi ya vipengee vya mfumo huenda visifanye kazi"</string>
     <string name="ok" msgid="5970060430562524910">"Sawa"</string>
     <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
     <string name="yes" msgid="5362982303337969312">"Sawa"</string>
@@ -1291,6 +1289,5 @@
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Sauti ya HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
-    <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) -->
-    <skip />
+    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kwisha"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 008ceb5..b6b3c88 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"ลำโพงแท่นชาร์จ"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"เสียง HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ระบบ"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 615d013..85ea80b 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Mga speaker ng dock"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI audio"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 7bafbe2..697bce6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Yuva hoparlörleri"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI ses"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a9a8a93..925d06b 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Loa đế"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"Âm thanh HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index aa0fb65..6b915ae 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"基座扬声器"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI 音频"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系统"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 345a149..546d039 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1288,7 +1288,6 @@
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"座架喇叭"</string>
     <string name="default_audio_route_name_hdmi" msgid="7986404173839007682">"HDMI 音訊"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
-    <!-- no translation found for bluetooth_a2dp_audio_route_name (8575624030406771015) -->
-    <skip />
+    <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3a7253b..9cd04e4 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -842,6 +842,12 @@
         <!-- The drawable for accessibility focused views. -->
         <attr name="accessibilityFocusedDrawable" format="reference" />
 
+        <!-- Drawable for WebView find-on-page dialogue's "next" button. @hide -->
+        <attr name="findOnPageNextDrawable" format="reference" />
+
+        <!-- Drawable for WebView find-on-page dialogue's "previous" button. @hide -->
+        <attr name="findOnPagePreviousDrawable" format="reference" />
+
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -5697,6 +5703,15 @@
              @hide -->
         <attr name="externalRouteEnabledDrawable" format="reference" />
 
+        <!-- The types of media routes the button and its resulting
+             chooser will filter by. -->
+        <attr name="mediaRouteTypes" format="integer">
+            <!-- Allow selection of live audio routes. -->
+            <enum name="liveAudio" value="0x1" />
+            <!-- Allow selection of user (app-specified) routes. -->
+            <enum name="user" value="0x800000" />
+        </attr>
+
         <attr name="minWidth" />
         <attr name="minHeight" />
     </declare-styleable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 946bfe6..303cf78 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3644,6 +3644,7 @@
   <public type="attr" name="fontFamily" id="0x010103ac" />
 
   <public type="attr" name="mediaRouteButtonStyle" id="0x010103ad" />
+  <public type="attr" name="mediaRouteTypes" id="0x010103ae" />
   <public type="style" name="Widget.Holo.MediaRouteButton" id="0x010301d5" />
   <public type="style" name="Widget.Holo.Light.MediaRouteButton" id="0x010301d6" />
   <public type="style" name="Widget.DeviceDefault.MediaRouteButton" id="0x010301d7" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 83d0f63..2f18944 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -153,6 +153,8 @@
                 ?android:attr/expandableListPreferredItemIndicatorLeft</item>
         <item name="expandableListPreferredChildIndicatorRight">
                 ?android:attr/expandableListPreferredItemIndicatorRight</item>
+        <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_dark</item>
+        <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_dark</item>
 
         <!-- Gallery attributes -->
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
@@ -467,6 +469,8 @@
         <item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item>
 
         <item name="mediaRouteButtonStyle">@android:style/Widget.DeviceDefault.Light.MediaRouteButton</item>
+        <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_light</item>
+        <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_Light} with no title bar -->
@@ -980,6 +984,8 @@
         <item name="expandableListPreferredItemIndicatorRight">0dip</item>
         <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
         <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
+        <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_dark</item>
+        <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_dark</item>
 
         <!-- Gallery attributes -->
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
@@ -1283,6 +1289,8 @@
         <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
 
         <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_light</item>
+        <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_light</item>
+        <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_light</item>
 
         <!-- Gallery attributes -->
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
diff --git a/docs/html/design/media/typography_sizes.png b/docs/html/design/media/typography_sizes.png
index eda1d99..fe6cdce 100644
--- a/docs/html/design/media/typography_sizes.png
+++ b/docs/html/design/media/typography_sizes.png
Binary files differ
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index 775e45d..c4e8bd6 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -139,7 +139,7 @@
 
     <ul>
       <li class="no-bullet with-icon tablet">
-        <p>Action bar icons for phones should be <strong>32x32 <acronym title="Density-independent pixels. One dp is one pixel on a 160 dpi screen.">dp</acronym></strong>.</p></li>
+        <p>Action bar icons for phones and tablets should be <strong>32x32 <acronym title="Density-independent pixels. One dp is one pixel on a 160 dpi screen.">dp</acronym></strong>.</p></li>
     </ul>
 
   </div>
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 418dc52..1b476027 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4243,6 +4243,7 @@
         public int mPlaybackVolumeHandling;
         public int mPlaybackStream;
         public int mPlaybackState;
+        public IRemoteVolumeObserver mRemoteVolumeObs;
 
         public void resetPlaybackInfo() {
             mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
@@ -4251,6 +4252,7 @@
             mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
             mPlaybackStream = AudioManager.STREAM_MUSIC;
             mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED;
+            mRemoteVolumeObs = null;
         }
 
         /** precondition: mediaIntent != null, eventReceiver != null */
@@ -4335,7 +4337,9 @@
                         "  -- state: " + rcse.mPlaybackState +
                         "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
                         "  -- vol: " + rcse.mPlaybackVolume +
-                        "  -- volMax: " + rcse.mPlaybackVolumeMax);
+                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
+                        "  -- volObs: " + rcse.mRemoteVolumeObs);
+                
             }
         }
         synchronized (mMainRemote) {
@@ -5018,6 +5022,20 @@
         }
     }
 
+    // FIXME send a message instead of updating the stack synchronously
+    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
+        synchronized(mRCStack) {
+            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+            while(stackIterator.hasNext()) {
+                RemoteControlStackEntry rcse = stackIterator.next();
+                if (rcse.mRccId == rccId) {
+                    rcse.mRemoteVolumeObs = rvo;
+                    break;
+                }
+            }
+        }
+    }
+
     /**
      * Checks if a remote client is active on the supplied stream type. Update the remote stream
      * volume state if found and playing
@@ -5100,23 +5118,24 @@
             // only handling discrete events
             return;
         }
-        String packageForRcc = null;
+        IRemoteVolumeObserver rvo = null;
         synchronized (mRCStack) {
             Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
             while(stackIterator.hasNext()) {
                 RemoteControlStackEntry rcse = stackIterator.next();
                 //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
                 if (rcse.mRccId == rccId) {
-                    packageForRcc = rcse.mReceiverComponent.getPackageName();
+                    rvo = rcse.mRemoteVolumeObs;
                     break;
                 }
             }
         }
-        if (packageForRcc != null) {
-            Intent intent = new Intent(Intent.ACTION_VOLUME_UPDATE);
-            intent.putExtra(Intent.EXTRA_VOLUME_UPDATE_DIRECTION, direction);
-            intent.setPackage(packageForRcc);
-            mContext.sendBroadcast(intent);
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(direction, -1);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching relative volume update", e);
+            }
         }
     }
 
@@ -5147,23 +5166,24 @@
             }
             rccId = mMainRemote.mRccId;
         }
-        String packageForRcc = null;
+        IRemoteVolumeObserver rvo = null;
         synchronized (mRCStack) {
             Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
             while(stackIterator.hasNext()) {
                 RemoteControlStackEntry rcse = stackIterator.next();
                 if (rcse.mRccId == rccId) {
                     //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    packageForRcc = rcse.mReceiverComponent.getPackageName();
+                    rvo = rcse.mRemoteVolumeObs;
                     break;
                 }
             }
         }
-        if (packageForRcc != null) {
-            Intent intent = new Intent(Intent.ACTION_VOLUME_UPDATE);
-            intent.putExtra(Intent.EXTRA_VOLUME_UPDATE_VALUE, vol);
-            intent.setPackage(packageForRcc);
-            mContext.sendBroadcast(intent);
+        if (rvo != null) {
+            try {
+                rvo.dispatchRemoteVolumeUpdate(0, vol);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error dispatching absolute volume update", e);
+            }
         }
     }
 
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 83483c6..854eb3f 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -24,6 +24,7 @@
 import android.media.IAudioRoutesObserver;
 import android.media.IRemoteControlClient;
 import android.media.IRemoteControlDisplay;
+import android.media.IRemoteVolumeObserver;
 import android.media.IRingtonePlayer;
 import android.net.Uri;
 import android.view.KeyEvent;
@@ -135,6 +136,7 @@
     oneway void setPlaybackInfoForRcc(int rccId, int what, int value);
            int  getRemoteStreamMaxVolume();
            int  getRemoteStreamVolume();
+    oneway void registerRemoteVolumeObserverForRcc(int rccId, in IRemoteVolumeObserver rvo);
 
     void startBluetoothSco(IBinder cb);
     void stopBluetoothSco(IBinder cb);
diff --git a/media/java/android/media/IRemoteVolumeObserver.aidl b/media/java/android/media/IRemoteVolumeObserver.aidl
new file mode 100644
index 0000000..7ff0c06
--- /dev/null
+++ b/media/java/android/media/IRemoteVolumeObserver.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+
+/**
+ * AIDL for the AudioService to report requests for remote volume update requests.
+ * @hide
+ */
+oneway interface IRemoteVolumeObserver {
+    void dispatchRemoteVolumeUpdate(int direction, int value);
+}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index a9e6e3d..a309c3f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -589,9 +589,46 @@
         RouteGroup mGroup;
         final RouteCategory mCategory;
         Drawable mIcon;
+        // playback information
+        int mPlaybackType = PLAYBACK_TYPE_LOCAL;
+        int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+        int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
+        int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
+        int mPlaybackStream = AudioManager.STREAM_MUSIC;
+        VolumeCallbackInfo mVcb;
 
         private Object mTag;
 
+        /**
+         * @hide (to be un-hidden)
+         * The default playback type, "local", indicating the presentation of the media is happening
+         * on the same device (e.g. a phone, a tablet) as where it is controlled from.
+         * @see #setPlaybackType(int)
+         */
+        public final static int PLAYBACK_TYPE_LOCAL = 0;
+        /**
+         * @hide (to be un-hidden)
+         * A playback type indicating the presentation of the media is happening on
+         * a different device (i.e. the remote device) than where it is controlled from.
+         * @see #setPlaybackType(int)
+         */
+        public final static int PLAYBACK_TYPE_REMOTE = 1;
+        /**
+         * @hide (to be un-hidden)
+         * Playback information indicating the playback volume is fixed, i.e. it cannot be
+         * controlled from this object. An example of fixed playback volume is a remote player,
+         * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
+         * than attenuate at the source.
+         * @see #setVolumeHandling(int)
+         */
+        public final static int PLAYBACK_VOLUME_FIXED = 0;
+        /**
+         * @hide (to be un-hidden)
+         * Playback information indicating the playback volume is variable and can be controlled
+         * from this object.
+         */
+        public final static int PLAYBACK_VOLUME_VARIABLE = 1;
+
         RouteInfo(RouteCategory category) {
             mCategory = category;
         }
@@ -685,6 +722,71 @@
             return mTag;
         }
 
+        /**
+         * @hide (to be un-hidden)
+         * @return the type of playback associated with this route
+         * @see UserRouteInfo#setPlaybackType(int)
+         */
+        public int getPlaybackType() {
+            return mPlaybackType;
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * @return the stream over which the playback associated with this route is performed
+         * @see UserRouteInfo#setPlaybackStream(int)
+         */
+        public int getPlaybackStream() {
+            return mPlaybackStream;
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * @return the volume at which the playback associated with this route is performed
+         * @see UserRouteInfo#setVolume(int)
+         */
+        public int getVolume() {
+            if (mPlaybackType == PLAYBACK_TYPE_LOCAL) {
+                int vol = 0;
+                try {
+                    vol = sStatic.mAudioService.getStreamVolume(mPlaybackStream);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error getting local stream volume", e);
+                }
+                return vol;
+            } else {
+                return mVolume;
+            }
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * @return the maximum volume at which the playback associated with this route is performed
+         * @see UserRouteInfo#setVolumeMax(int)
+         */
+        public int getVolumeMax() {
+            if (mPlaybackType == PLAYBACK_TYPE_LOCAL) {
+                int volMax = 0;
+                try {
+                    volMax = sStatic.mAudioService.getStreamMaxVolume(mPlaybackStream);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error getting local stream volume", e);
+                }
+                return volMax;
+            } else {
+                return mVolumeMax;
+            }
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * @return how volume is handling on the route
+         * @see UserRouteInfo#setVolumeHandling(int)
+         */
+        public int getVolumeHandling() {
+            return mVolumeHandling;
+        }
+
         void setStatusInt(CharSequence status) {
             if (!status.equals(mStatus)) {
                 mStatus = status;
@@ -695,6 +797,24 @@
             }
         }
 
+        final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() {
+            public void dispatchRemoteVolumeUpdate(final int direction, final int value) {
+                sStatic.mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                      //Log.d(TAG, "dispatchRemoteVolumeUpdate dir=" + direction + " val=" + value);
+                        if (mVcb != null) {
+                            if (direction != 0) {
+                                mVcb.vcb.onVolumeUpdateRequest(mVcb.route, direction);
+                            } else {
+                                mVcb.vcb.onVolumeSetRequest(mVcb.route, value);
+                            }
+                        }
+                    }
+                });
+            }
+        };
+
         void routeUpdated() {
             updateRoute(this);
         }
@@ -757,10 +877,14 @@
          * RemoteControlClient will be used to reflect and update information
          * such as route volume info in related UIs.</p>
          *
+         * <p>The RemoteControlClient must have been previously registered with
+         * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.</p>
+         *
          * @param rcc RemoteControlClient associated with this route
          */
         public void setRemoteControlClient(RemoteControlClient rcc) {
             mRcc = rcc;
+            updatePlaybackInfoOnRcc();
         }
 
         /**
@@ -792,6 +916,111 @@
         public void setIconResource(int resId) {
             setIconDrawable(sStatic.mResources.getDrawable(resId));
         }
+
+        /**
+         * @hide (to be un-hidden)
+         * Set a callback to be notified of volume update requests
+         * @param vcb
+         */
+        public void setVolumeCallback(VolumeCallback vcb) {
+            mVcb = new VolumeCallbackInfo(vcb, this);
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * Defines whether playback associated with this route is "local"
+         *    ({@link RouteInfo#PLAYBACK_TYPE_LOCAL}) or "remote"
+         *    ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}).
+         * @param type
+         */
+        public void setPlaybackType(int type) {
+            if (mPlaybackType != type) {
+                mPlaybackType = type;
+                setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type);
+            }
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * Defines whether volume for the playback associated with this route is fixed
+         * ({@link RouteInfo#PLAYBACK_VOLUME_FIXED}) or can modified
+         * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}).
+         * @param volumeHandling
+         */
+        public void setVolumeHandling(int volumeHandling) {
+            if (mVolumeHandling != volumeHandling) {
+                mVolumeHandling = volumeHandling;
+                setPlaybackInfoOnRcc(
+                        RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling);
+            }
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * Defines at what volume the playback associated with this route is performed (for user
+         * feedback purposes). This information is only used when the playback is not local.
+         * @param volume
+         */
+        public void setVolume(int volume) {
+            if (mVolume != volume) {
+                mVolume = volume;
+                setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume);
+            }
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * Defines the maximum volume at which the playback associated with this route is performed
+         * (for user feedback purposes). This information is only used when the playback is not
+         * local.
+         * @param volumeMax
+         */
+        public void setVolumeMax(int volumeMax) {
+            if (mVolumeMax != volumeMax) {
+                mVolumeMax = volumeMax;
+                setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax);
+            }
+        }
+
+        /**
+         * @hide (to be un-hidden)
+         * Defines over what stream type the media is presented.
+         * @param stream
+         */
+        public void setPlaybackStream(int stream) {
+            if (mPlaybackStream != stream) {
+                mPlaybackStream = stream;
+                setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream);
+            }
+        }
+
+        private void updatePlaybackInfoOnRcc() {
+            if ((mRcc != null) && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) {
+                mRcc.setPlaybackInformation(
+                        RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax);
+                mRcc.setPlaybackInformation(
+                        RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume);
+                mRcc.setPlaybackInformation(
+                        RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling);
+                mRcc.setPlaybackInformation(
+                        RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream);
+                mRcc.setPlaybackInformation(
+                        RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType);
+                // let AudioService know whom to call when remote volume needs to be updated
+                try {
+                    sStatic.mAudioService.registerRemoteVolumeObserverForRcc(
+                            mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Error registering remote volume observer", e);
+                }
+            }
+        }
+
+        private void setPlaybackInfoOnRcc(int what, int value) {
+            if (mRcc != null) {
+                mRcc.setPlaybackInformation(what, value);
+            }
+        }
     }
 
     /**
@@ -1206,4 +1435,44 @@
         }
 
     }
+
+    static class VolumeCallbackInfo {
+        public final VolumeCallback vcb;
+        public final RouteInfo route;
+
+        public VolumeCallbackInfo(VolumeCallback vcb, RouteInfo route) {
+            this.vcb = vcb;
+            this.route = route;
+        }
+    }
+
+    /**
+     * @hide (to be un-hidden)
+     * Interface for receiving events about volume changes.
+     * All methods of this interface will be called from the application's main thread.
+     *
+     * <p>A VolumeCallback will only receive events relevant to routes that the callback
+     * was registered for.</p>
+     *
+     * @see UserRouteInfo#setVolumeCallback(VolumeCallback)
+     */
+    public static abstract class VolumeCallback {
+        /**
+         * Called when the volume for the route should be increased or decreased.
+         * @param info the route affected by this event
+         * @param direction an integer indicating whether the volume is to be increased
+         *     (positive value) or decreased (negative value).
+         *     For bundled changes, the absolute value indicates the number of changes
+         *     in the same direction, e.g. +3 corresponds to three "volume up" changes.
+         */
+        public abstract void onVolumeUpdateRequest(RouteInfo info, int direction);
+        /**
+         * Called when the volume for the route should be set to the given value
+         * @param info the route affected by this event
+         * @param volume an integer indicating the new volume value that should be used, always
+         *     between 0 and the value set by {@link UserRouteInfo#setVolumeMax(int)}.
+         */
+        public abstract void onVolumeSetRequest(RouteInfo info, int volume);
+    }
+
 }
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 5b8035e..79f9d37 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -134,13 +134,13 @@
     public final static int PLAYSTATE_NONE               = 0;
 
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * The default playback type, "local", indicating the presentation of the media is happening on
      * the same device (e.g. a phone, a tablet) as where it is controlled from.
      */
     public final static int PLAYBACK_TYPE_LOCAL = 0;
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * A playback type indicating the presentation of the media is happening on
      * a different device (i.e. the remote device) than where it is controlled from.
      */
@@ -148,7 +148,7 @@
     private final static int PLAYBACK_TYPE_MIN = PLAYBACK_TYPE_LOCAL;
     private final static int PLAYBACK_TYPE_MAX = PLAYBACK_TYPE_REMOTE;
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * Playback information indicating the playback volume is fixed, i.e. it cannot be controlled
      * from this object. An example of fixed playback volume is a remote player, playing over HDMI
      * where the user prefer to control the volume on the HDMI sink, rather than attenuate at the
@@ -157,7 +157,7 @@
      */
     public final static int PLAYBACK_VOLUME_FIXED = 0;
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * Playback information indicating the playback volume is variable and can be controlled from
      * this object.
      * @see #PLAYBACKINFO_VOLUME_HANDLING.
@@ -173,34 +173,34 @@
     //==========================================
     // Public keys for playback information
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * Playback information that defines the type of playback associated with this
      * RemoteControlClient. See {@link #PLAYBACK_TYPE_LOCAL} and {@link #PLAYBACK_TYPE_REMOTE}.
      */
     public final static int PLAYBACKINFO_PLAYBACK_TYPE = 1;
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * Playback information that defines at what volume the playback associated with this
      * RemoteControlClient is performed. This information is only used when the playback type is not
      * local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
      */
     public final static int PLAYBACKINFO_VOLUME = 2;
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * Playback information that defines the maximum volume volume value that is supported
      * by the playback associated with this RemoteControlClient. This information is only used
      * when the playback type is not local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
      */
     public final static int PLAYBACKINFO_VOLUME_MAX = 3;
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * Playback information that defines how volume is handled for the presentation of the media.
      * @see #PLAYBACK_VOLUME_FIXED
      * @see #PLAYBACK_VOLUME_VARIABLE
      */
     public final static int PLAYBACKINFO_VOLUME_HANDLING = 4;
     /**
-     * @hide (to be un-hidden)
+     * @hide
      * Playback information that defines over what stream type the media is presented.
      */
     public final static int PLAYBACKINFO_USES_STREAM = 5;
@@ -642,7 +642,7 @@
     private int mPlaybackStream = AudioManager.STREAM_MUSIC;
 
     /**
-     * @hide  (to be un-hidden)
+     * @hide
      * Set information describing information related to the playback of media so the system
      * can implement additional behavior to handle non-local playback usecases.
      * @param what a key to specify the type of information to set. Valid keys are
@@ -713,7 +713,7 @@
     }
 
     /**
-     * @hide  (to be un-hidden)
+     * @hide
      * Return playback information represented as an integer value.
      * @param what a key to specify the type of information to retrieve. Valid keys are
      *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
@@ -899,6 +899,13 @@
         mRcseId = id;
     }
 
+    /**
+     * @hide
+     */
+    public int getRcseId() {
+        return mRcseId;
+    }
+
     private EventHandler mEventHandler;
     private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
     private final static int MSG_REQUEST_METADATA = 2;
diff --git a/packages/SystemUI/res/drawable/navbar_search_outerring.xml b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
index 8a8785f..689dbf0 100644
--- a/packages/SystemUI/res/drawable/navbar_search_outerring.xml
+++ b/packages/SystemUI/res/drawable/navbar_search_outerring.xml
@@ -19,5 +19,5 @@
     <size android:height="@dimen/navbar_search_outerring_diameter"
         android:width="@dimen/navbar_search_outerring_diameter" />
     <solid android:color="#00000000" />
-    <stroke android:color="#00000000" android:width="2dp" />
+    <stroke android:color="#40ffffff" android:width="2dp" />
 </shape>
diff --git a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
index f91e5d6..c8a120d 100644
--- a/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_search_panel.xml
@@ -54,7 +54,7 @@
                 prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
                 prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
-                prvandroid:feedbackCount="1"
+                prvandroid:feedbackCount="0"
                 prvandroid:vibrationDuration="@integer/config_vibration_duration"
                 prvandroid:alwaysTrackFinger="true"
                 prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
diff --git a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
index 2556aca..1e4bb57 100644
--- a/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_search_panel.xml
@@ -54,7 +54,7 @@
                 prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
                 prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
                 prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
-                prvandroid:feedbackCount="1"
+                prvandroid:feedbackCount="0"
                 prvandroid:vibrationDuration="@integer/config_vibration_duration"
                 prvandroid:alwaysTrackFinger="true"
                 prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
index 459fac9..3b6c52e 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_search_panel.xml
@@ -40,7 +40,7 @@
         prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
         prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
         prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
-        prvandroid:feedbackCount="1"
+        prvandroid:feedbackCount="0"
         prvandroid:vibrationDuration="@integer/config_vibration_duration"
         prvandroid:alwaysTrackFinger="true"
         prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
diff --git a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
index d2e26db..8c2360e 100644
--- a/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
+++ b/packages/SystemUI/res/layout-sw720dp/status_bar_search_panel.xml
@@ -41,7 +41,7 @@
         prvandroid:outerRadius="@dimen/navbar_search_outerring_radius"
         prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"
         prvandroid:snapMargin="@dimen/navbar_search_snap_margin"
-        prvandroid:feedbackCount="1"
+        prvandroid:feedbackCount="0"
         prvandroid:vibrationDuration="@integer/config_vibration_duration"
         prvandroid:alwaysTrackFinger="true"
         prvandroid:glowRadius="@*android:dimen/glowpadview_glow_radius"
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index acab41e..475fb6d 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -53,7 +53,6 @@
     private static final String ASSIST_ICON_METADATA_NAME =
             "com.android.systemui.action_assist_icon";
     private final Context mContext;
-    private final SearchManager mSearchManager;
     private BaseStatusBar mBar;
     private StatusBarTouchProxy mStatusBarTouchProxy;
 
@@ -68,25 +67,13 @@
     public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         mContext = context;
-        mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        if (mSearchManager == null) {
-            Slog.w(TAG, "Search manager not available");
-        }
-    }
-
-    public boolean isAssistantAvailable() {
-        return mSearchManager != null && mSearchManager.isAssistantAvailable();
-    }
-
-    private Intent getAssistIntent() {
-        return mSearchManager != null ? mSearchManager.getAssistIntent() : null;
     }
 
     private void startAssistActivity() {
         // Close Recent Apps if needed
         mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
         // Launch Assist
-        Intent intent = getAssistIntent();
+        Intent intent = SearchManager.getAssistIntent(mContext);
         if (intent == null) return;
         try {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
@@ -150,19 +137,17 @@
         // TODO: fetch views
         mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
         mGlowPadView.setOnTriggerListener(mGlowPadViewListener);
-        if (mSearchManager != null) {
-            ComponentName component = mSearchManager.getGlobalSearchActivity();
-            if (component != null) {
-                if (!mGlowPadView.replaceTargetDrawablesIfPresent(component,
-                        ASSIST_ICON_METADATA_NAME,
-                        com.android.internal.R.drawable.ic_action_assist_generic)) {
-                    Slog.w(TAG, "Couldn't grab icon from component " + component);
-                }
-            } else {
-                Slog.w(TAG, "No search icon specified in component " + component);
+    }
+
+    private void maybeSwapSearchIcon() {
+        Intent intent = SearchManager.getAssistIntent(mContext);
+        if (intent != null) {
+            ComponentName component = intent.getComponent();
+            if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component,
+                    ASSIST_ICON_METADATA_NAME,
+                    com.android.internal.R.drawable.ic_action_assist_generic)) {
+                if (DEBUG) Slog.v(TAG, "Couldn't grab icon for component " + component);
             }
-        } else {
-            Slog.w(TAG, "No SearchManager");
         }
     }
 
@@ -210,6 +195,7 @@
         }
         mShowing = show;
         if (show) {
+            maybeSwapSearchIcon();
             if (getVisibility() != View.VISIBLE) {
                 setVisibility(View.VISIBLE);
                 // Don't start the animation until we've created the layer, which is done
@@ -289,4 +275,8 @@
         transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
         return transitioner;
     }
+
+    public boolean isAssistantAvailable() {
+        return SearchManager.getAssistIntent(mContext) != null;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 33dda09..ec954fe 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -83,7 +83,6 @@
     private View mUnlockWidget;
     private boolean mCameraDisabled;
     private boolean mSearchDisabled;
-    private SearchManager mSearchManager;
     // Is there a vibrator
     private final boolean mHasVibrator;
 
@@ -253,23 +252,6 @@
         }
     }
 
-    private boolean isAssistantAvailable() {
-        SearchManager searchManager = getSearchManager();
-        return searchManager != null && searchManager.isAssistantAvailable();
-    }
-
-    private Intent getAssistIntent() {
-        SearchManager searchManager = getSearchManager();
-        return searchManager != null ? searchManager.getAssistIntent() : null;
-    }
-
-    private SearchManager getSearchManager() {
-        if (mSearchManager == null) {
-            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
-        }
-        return mSearchManager;
-    }
-
     class GlowPadViewMethods implements GlowPadView.OnTriggerListener,
             UnlockWidgetCommonMethods {
         private final GlowPadView mGlowPadView;
@@ -297,27 +279,21 @@
 
             // Update the search icon with drawable from the search .apk
             if (!mSearchDisabled) {
-                SearchManager searchManager = getSearchManager();
-                if (searchManager != null) {
-                    ComponentName component = searchManager.getGlobalSearchActivity();
-                    if (component != null) {
-                        // XXX Hack. We need to substitute the icon here but haven't formalized
-                        // the public API. The "_google" metadata will be going away, so
-                        // DON'T USE IT!
-                        boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component,
-                                ASSIST_ICON_METADATA_NAME + "_google",
-                                com.android.internal.R.drawable.ic_action_assist_generic);
+                Intent intent = SearchManager.getAssistIntent(mContext);
+                if (intent != null) {
+                    // XXX Hack. We need to substitute the icon here but haven't formalized
+                    // the public API. The "_google" metadata will be going away, so
+                    // DON'T USE IT!
+                    ComponentName component = intent.getComponent();
+                    boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component,
+                            ASSIST_ICON_METADATA_NAME + "_google",
+                            com.android.internal.R.drawable.ic_action_assist_generic);
 
-                        if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component,
-                                    ASSIST_ICON_METADATA_NAME,
-                                    com.android.internal.R.drawable.ic_action_assist_generic)) {
-                                Slog.w(TAG, "Couldn't grab icon from package " + component);
-                        }
-                    } else {
-                        Slog.w(TAG, "No search icon specified in package " + component);
+                    if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component,
+                                ASSIST_ICON_METADATA_NAME,
+                                com.android.internal.R.drawable.ic_action_assist_generic)) {
+                            Slog.w(TAG, "Couldn't grab icon from package " + component);
                     }
-                } else {
-                    Slog.w(TAG, "No SearchManager");
                 }
             }
 
@@ -337,7 +313,7 @@
             final int resId = mGlowPadView.getResourceIdForTarget(target);
             switch (resId) {
                 case com.android.internal.R.drawable.ic_action_assist_generic:
-                    Intent assistIntent = getAssistIntent();
+                    Intent assistIntent = SearchManager.getAssistIntent(mContext);
                     if (assistIntent != null) {
                         launchActivity(assistIntent);
                     } else {
@@ -550,7 +526,7 @@
         } else if (disabledBySimState) {
             Log.v(TAG, "Camera disabled by Sim State");
         }
-        boolean searchActionAvailable = isAssistantAvailable();
+        boolean searchActionAvailable = SearchManager.getAssistIntent(mContext) != null;
         mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent;
         mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent;
         mUnlockWidgetMethods.updateResources();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index dde9db9..beeea8e 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2081,6 +2081,8 @@
         Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         try {
+            // TODO: This only stops the factory-installed search manager.  
+            // Need to formalize an API to handle others
             SearchManager searchManager = getSearchManager();
             if (searchManager != null) {
                 searchManager.stopSearch();
@@ -2093,19 +2095,15 @@
 
     private void launchAssistAction() {
         sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
-
-        SearchManager searchManager = getSearchManager();
-        if (searchManager != null) {
-            Intent intent = searchManager.getAssistIntent();
-            if (intent != null) {
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                try {
-                    mContext.startActivity(intent);
-                } catch (ActivityNotFoundException e) {
-                    Slog.w(TAG, "No activity to handle assist action.", e);
-                }
+        Intent intent = SearchManager.getAssistIntent(mContext);
+        if (intent != null) {
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            try {
+                mContext.startActivity(intent);
+            } catch (ActivityNotFoundException e) {
+                Slog.w(TAG, "No activity to handle assist action.", e);
             }
         }
     }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index e101377..5cd4beb 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -8257,6 +8257,9 @@
 
         mAppTransitionRunning = false;
         // Restore window app tokens to the ActivityManager views
+        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
+            mAnimatingAppTokens.get(i).sendingToBottom = false;
+        }
         mAnimatingAppTokens.clear();
         mAnimatingAppTokens.addAll(mAppTokens);
         rebuildAppWindowListLocked();
@@ -9120,6 +9123,8 @@
 
             // If this window's application has been removed, just skip it.
             if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
+                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
+                        ? "removed" : "sendingToBottom"));
                 continue;
             }
 
diff --git a/tests/Assistant/Android.mk b/tests/Assistant/Android.mk
new file mode 100644
index 0000000..bf8cc29
--- /dev/null
+++ b/tests/Assistant/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Assistant
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/Assistant/AndroidManifest.xml b/tests/Assistant/AndroidManifest.xml
new file mode 100644
index 0000000..b5d4d51
--- /dev/null
+++ b/tests/Assistant/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.android.test.assistant">
+
+    <application android:label="@string/activity_title">
+
+        <activity android:name=".AssistActivity"
+            android:theme="@android:style/Theme.NoTitleBar">
+
+            <!-- Handle assist intent -->
+            <intent-filter>
+                <action android:name="android.intent.action.ASSIST" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+
+            <!-- Provide icon for search -->
+            <meta-data android:name="com.android.systemui.action_assist_icon"
+                    android:resource="@drawable/ic_action_assist" />
+
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png b/tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png
new file mode 100644
index 0000000..cea8ac4
--- /dev/null
+++ b/tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png b/tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png
new file mode 100644
index 0000000..bb7702d
--- /dev/null
+++ b/tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png b/tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png
new file mode 100644
index 0000000..5841d82
--- /dev/null
+++ b/tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png b/tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png
new file mode 100644
index 0000000..3851f03
--- /dev/null
+++ b/tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png
new file mode 100644
index 0000000..778db19
--- /dev/null
+++ b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png
new file mode 100644
index 0000000..ad49125
--- /dev/null
+++ b/tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png
Binary files differ
diff --git a/tests/Assistant/res/drawable/ic_action_assist.xml b/tests/Assistant/res/drawable/ic_action_assist.xml
new file mode 100644
index 0000000..05c4bf5
--- /dev/null
+++ b/tests/Assistant/res/drawable/ic_action_assist.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_action_assist_normal" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="true"
+        android:state_focused="false"
+        android:drawable="@drawable/ic_action_assist_activated" />
+
+    <item
+        android:state_enabled="true"
+        android:state_active="false"
+        android:state_focused="true"
+        android:drawable="@drawable/ic_action_assist_activated" />
+
+</selector>
diff --git a/tests/Assistant/res/layout/assist_intent_activity.xml b/tests/Assistant/res/layout/assist_intent_activity.xml
new file mode 100644
index 0000000..49785bc
--- /dev/null
+++ b/tests/Assistant/res/layout/assist_intent_activity.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, 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.
+*/
+-->
+
+<!-- This is the general lock screen which shows information about the
+  state of the device, as well as instructions on how to get past it
+  depending on the state of the device.  It is the same for landscape
+  and portrait.-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+    <TextView android:id="@+id/label"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/search_label"
+    />
+
+    <EditText android:id="@+id/search_input"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+    />
+
+</LinearLayout>
+
diff --git a/tests/Assistant/res/values/strings.xml b/tests/Assistant/res/values/strings.xml
new file mode 100644
index 0000000..a59c1ef
--- /dev/null
+++ b/tests/Assistant/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="activity_title">Assistant</string>
+    <string name="search_label">Orilla Search Engine</string>
+</resources>
diff --git a/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java b/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java
new file mode 100644
index 0000000..51894a1
--- /dev/null
+++ b/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.assistant;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.google.android.test.assistant.R;
+
+public class AssistActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.assist_intent_activity);
+    }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 66481fd..daf520b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -470,7 +470,7 @@
         if (pair == null) {
             pair = sDynamicIds.resolveId(value);
             if (pair == null) {
-                System.out.println(String.format("Missing id: %1$08X (%1$d)", value));
+                //System.out.println(String.format("Missing id: %1$08X (%1$d)", value));
             }
         }
         return pair;