Merge "Fix incorrent page range parsing when custom print options used." into klp-dev
diff --git a/Android.mk b/Android.mk
index f97849c..b0a27e4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -251,10 +251,14 @@
 	media/java/android/media/IAudioService.aidl \
 	media/java/android/media/IAudioFocusDispatcher.aidl \
 	media/java/android/media/IAudioRoutesObserver.aidl \
+	media/java/android/media/IMediaRouterClient.aidl \
+	media/java/android/media/IMediaRouterService.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/IRemoteDisplayCallback.aidl \
+	media/java/android/media/IRemoteDisplayProvider.aidl \
 	media/java/android/media/IRemoteVolumeObserver.aidl \
 	media/java/android/media/IRingtonePlayer.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index c18f542..0344d26 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -107,7 +107,7 @@
                 "       am switch-user <USER_ID>\n" +
                 "       am stop-user <USER_ID>\n" +
                 "       am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" +
-                "       am stack movetask <STACK_ID> <TASK_ID> [true|false]\n" +
+                "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <WEIGHT>\n" +
                 "       am stack boxes\n" +
                 "       am stack box <STACK_BOX_ID>\n" +
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index bb04063..7ca3459 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2272,9 +2272,12 @@
     public static void dumpPackageStateStatic(FileDescriptor fd, String packageName) {
         FileOutputStream fout = new FileOutputStream(fd);
         PrintWriter pw = new FastPrintWriter(fout);
-        dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName });
+        dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] {
+                "-a", "package", packageName });
         pw.println();
-        dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName });
+        dumpService(pw, fd, "meminfo", new String[] { "--local", packageName });
+        pw.println();
+        dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { "-a", packageName });
         pw.println();
         dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName });
         pw.println();
@@ -2296,7 +2299,7 @@
             pw.flush();
             tp = new TransferPipe();
             tp.setBufferPrefix("  ");
-            service.dump(tp.getWriteFd().getFileDescriptor(), args);
+            service.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
             tp.go(fd);
         } catch (Throwable e) {
             if (tp != null) {
diff --git a/core/java/android/app/MediaRouteActionProvider.java b/core/java/android/app/MediaRouteActionProvider.java
index 63b641c..dffa969 100644
--- a/core/java/android/app/MediaRouteActionProvider.java
+++ b/core/java/android/app/MediaRouteActionProvider.java
@@ -16,10 +16,7 @@
 
 package android.app;
 
-import com.android.internal.app.MediaRouteChooserDialogFragment;
-
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.media.MediaRouter;
 import android.media.MediaRouter.RouteInfo;
 import android.util.Log;
@@ -30,22 +27,38 @@
 
 import java.lang.ref.WeakReference;
 
+/**
+ * The media route action provider displays a {@link MediaRouteButton media route button}
+ * in the application's {@link ActionBar} to allow the user to select routes and
+ * to control the currently selected route.
+ * <p>
+ * The application must specify the kinds of routes that the user should be allowed
+ * to select by specifying the route types with the {@link #setRouteTypes} method.
+ * </p><p>
+ * Refer to {@link MediaRouteButton} for a description of the button that will
+ * appear in the action bar menu.  Note that instead of disabling the button
+ * when no routes are available, the action provider will instead make the
+ * menu item invisible.  In this way, the button will only be visible when it
+ * is possible for the user to discover and select a matching route.
+ * </p>
+ */
 public class MediaRouteActionProvider extends ActionProvider {
     private static final String TAG = "MediaRouteActionProvider";
 
-    private Context mContext;
-    private MediaRouter mRouter;
-    private MenuItem mMenuItem;
-    private MediaRouteButton mView;
+    private final Context mContext;
+    private final MediaRouter mRouter;
+    private final MediaRouterCallback mCallback;
+
     private int mRouteTypes;
+    private MediaRouteButton mButton;
     private View.OnClickListener mExtendedSettingsListener;
-    private RouterCallback mCallback;
 
     public MediaRouteActionProvider(Context context) {
         super(context);
+
         mContext = context;
         mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
-        mCallback = new RouterCallback(this);
+        mCallback = new MediaRouterCallback(this);
 
         // Start with live audio by default.
         // TODO Update this when new route types are added; segment by API level
@@ -53,80 +66,74 @@
         setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
     }
 
+    /**
+     * Sets the types of routes that will be shown in the media route chooser dialog
+     * launched by this button.
+     *
+     * @param types The route types to match.
+     */
     public void setRouteTypes(int types) {
-        if (mRouteTypes == types) return;
-        if (mRouteTypes != 0) {
-            mRouter.removeCallback(mCallback);
+        if (mRouteTypes != types) {
+            // FIXME: We currently have no way of knowing whether the action provider
+            // is still needed by the UI.  Unfortunately this means the action provider
+            // may leak callbacks until garbage collection occurs.  This may result in
+            // media route providers doing more work than necessary in the short term
+            // while trying to discover routes that are no longer of interest to the
+            // application.  To solve this problem, the action provider will need some
+            // indication from the framework that it is being destroyed.
+            if (mRouteTypes != 0) {
+                mRouter.removeCallback(mCallback);
+            }
+            mRouteTypes = types;
+            if (types != 0) {
+                mRouter.addCallback(types, mCallback,
+                        MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+            }
+            refreshRoute();
+
+            if (mButton != null) {
+                mButton.setRouteTypes(mRouteTypes);
+            }
         }
-        mRouteTypes = types;
-        if (types != 0) {
-            mRouter.addCallback(types, mCallback);
-        }
-        if (mView != null) {
-            mView.setRouteTypes(mRouteTypes);
+    }
+
+    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
+        mExtendedSettingsListener = listener;
+        if (mButton != null) {
+            mButton.setExtendedSettingsClickListener(listener);
         }
     }
 
     @Override
+    @SuppressWarnings("deprecation")
     public View onCreateActionView() {
         throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead.");
     }
 
     @Override
     public View onCreateActionView(MenuItem item) {
-        if (mMenuItem != null || mView != null) {
+        if (mButton != null) {
             Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " +
                     "with a menu item. Don't reuse MediaRouteActionProvider instances! " +
                     "Abandoning the old one...");
         }
-        mMenuItem = item;
-        mView = new MediaRouteButton(mContext);
-        mView.setCheatSheetEnabled(true);
-        mView.setRouteTypes(mRouteTypes);
-        mView.setExtendedSettingsClickListener(mExtendedSettingsListener);
-        mView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+
+        mButton = new MediaRouteButton(mContext);
+        mButton.setCheatSheetEnabled(true);
+        mButton.setRouteTypes(mRouteTypes);
+        mButton.setExtendedSettingsClickListener(mExtendedSettingsListener);
+        mButton.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
-        return mView;
+        return mButton;
     }
 
     @Override
     public boolean onPerformDefaultAction() {
-        final FragmentManager fm = getActivity().getFragmentManager();
-        // See if one is already attached to this activity.
-        MediaRouteChooserDialogFragment dialogFragment =
-                (MediaRouteChooserDialogFragment) fm.findFragmentByTag(
-                MediaRouteChooserDialogFragment.FRAGMENT_TAG);
-        if (dialogFragment != null) {
-            Log.w(TAG, "onPerformDefaultAction(): Chooser dialog already showing!");
-            return false;
+        if (mButton != null) {
+            return mButton.showDialogInternal();
         }
-
-        dialogFragment = new MediaRouteChooserDialogFragment();
-        dialogFragment.setExtendedSettingsClickListener(mExtendedSettingsListener);
-        dialogFragment.setRouteTypes(mRouteTypes);
-        dialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG);
-        return true;
-    }
-
-    private Activity getActivity() {
-        // Gross way of unwrapping the Activity so we can get the FragmentManager
-        Context context = mContext;
-        while (context instanceof ContextWrapper && !(context instanceof Activity)) {
-            context = ((ContextWrapper) context).getBaseContext();
-        }
-        if (!(context instanceof Activity)) {
-            throw new IllegalStateException("The MediaRouteActionProvider's Context " +
-                    "is not an Activity.");
-        }
-
-        return (Activity) context;
-    }
-
-    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
-        mExtendedSettingsListener = listener;
-        if (mView != null) {
-            mView.setExtendedSettingsClickListener(listener);
-        }
+        return false;
     }
 
     @Override
@@ -136,36 +143,43 @@
 
     @Override
     public boolean isVisible() {
-        return mRouter.getRouteCount() > 1;
+        return mRouter.isRouteAvailable(mRouteTypes,
+                MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
     }
 
-    private static class RouterCallback extends MediaRouter.SimpleCallback {
-        private WeakReference<MediaRouteActionProvider> mAp;
+    private void refreshRoute() {
+        refreshVisibility();
+    }
 
-        RouterCallback(MediaRouteActionProvider ap) {
-            mAp = new WeakReference<MediaRouteActionProvider>(ap);
+    private static class MediaRouterCallback extends MediaRouter.SimpleCallback {
+        private final WeakReference<MediaRouteActionProvider> mProviderWeak;
+
+        public MediaRouterCallback(MediaRouteActionProvider provider) {
+            mProviderWeak = new WeakReference<MediaRouteActionProvider>(provider);
         }
 
         @Override
         public void onRouteAdded(MediaRouter router, RouteInfo info) {
-            final MediaRouteActionProvider ap = mAp.get();
-            if (ap == null) {
-                router.removeCallback(this);
-                return;
-            }
-
-            ap.refreshVisibility();
+            refreshRoute(router);
         }
 
         @Override
         public void onRouteRemoved(MediaRouter router, RouteInfo info) {
-            final MediaRouteActionProvider ap = mAp.get();
-            if (ap == null) {
-                router.removeCallback(this);
-                return;
-            }
+            refreshRoute(router);
+        }
 
-            ap.refreshVisibility();
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo info) {
+            refreshRoute(router);
+        }
+
+        private void refreshRoute(MediaRouter router) {
+            MediaRouteActionProvider provider = mProviderWeak.get();
+            if (provider != null) {
+                provider.refreshRoute();
+            } else {
+                router.removeCallback(this);
+            }
         }
     }
 }
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index 7e0a27a..a7982f4 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -17,7 +17,7 @@
 package android.app;
 
 import com.android.internal.R;
-import com.android.internal.app.MediaRouteChooserDialogFragment;
+import com.android.internal.app.MediaRouteDialogPresenter;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -30,7 +30,6 @@
 import android.media.MediaRouter.RouteInfo;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.SoundEffectConstants;
@@ -38,17 +37,15 @@
 import android.widget.Toast;
 
 public class MediaRouteButton extends View {
-    private static final String TAG = "MediaRouteButton";
+    private final MediaRouter mRouter;
+    private final MediaRouterCallback mCallback;
 
-    private MediaRouter mRouter;
-    private final MediaRouteCallback mRouterCallback = new MediaRouteCallback();
     private int mRouteTypes;
 
     private boolean mAttachedToWindow;
 
     private Drawable mRemoteIndicator;
     private boolean mRemoteActive;
-    private boolean mToggleMode;
     private boolean mCheatSheetEnabled;
     private boolean mIsConnecting;
 
@@ -56,12 +53,13 @@
     private int mMinHeight;
 
     private OnClickListener mExtendedSettingsClickListener;
-    private MediaRouteChooserDialogFragment mDialogFragment;
 
+    // The checked state is used when connected to a remote route.
     private static final int[] CHECKED_STATE_SET = {
         R.attr.state_checked
     };
 
+    // The activated state is used while connecting to a remote route.
     private static final int[] ACTIVATED_STATE_SET = {
         R.attr.state_activated
     };
@@ -78,6 +76,7 @@
         super(context, attrs, defStyleAttr);
 
         mRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        mCallback = new MediaRouterCallback();
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 com.android.internal.R.styleable.MediaRouteButton, defStyleAttr, 0);
@@ -98,19 +97,87 @@
         setRouteTypes(routeTypes);
     }
 
-    private void setRemoteIndicatorDrawable(Drawable d) {
-        if (mRemoteIndicator != null) {
-            mRemoteIndicator.setCallback(null);
-            unscheduleDrawable(mRemoteIndicator);
+    /**
+     * Gets the media route types for filtering the routes that the user can
+     * select using the media route chooser dialog.
+     *
+     * @return The route types.
+     */
+    public int getRouteTypes() {
+        return mRouteTypes;
+    }
+
+    /**
+     * Sets the types of routes that will be shown in the media route chooser dialog
+     * launched by this button.
+     *
+     * @param types The route types to match.
+     */
+    public void setRouteTypes(int types) {
+        if (mRouteTypes != types) {
+            if (mAttachedToWindow && mRouteTypes != 0) {
+                mRouter.removeCallback(mCallback);
+            }
+
+            mRouteTypes = types;
+
+            if (mAttachedToWindow && types != 0) {
+                mRouter.addCallback(types, mCallback,
+                        MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+            }
+
+            refreshRoute();
         }
-        mRemoteIndicator = d;
-        if (d != null) {
-            d.setCallback(this);
-            d.setState(getDrawableState());
-            d.setVisible(getVisibility() == VISIBLE, false);
+    }
+
+    public void setExtendedSettingsClickListener(OnClickListener listener) {
+        mExtendedSettingsClickListener = listener;
+    }
+
+    /**
+     * Show the route chooser or controller dialog.
+     * <p>
+     * If the default route is selected or if the currently selected route does
+     * not match the {@link #getRouteTypes route types}, then shows the route chooser dialog.
+     * Otherwise, shows the route controller dialog to offer the user
+     * a choice to disconnect from the route or perform other control actions
+     * such as setting the route's volume.
+     * </p><p>
+     * This will attach a {@link DialogFragment} to the containing Activity.
+     * </p>
+     */
+    public void showDialog() {
+        showDialogInternal();
+    }
+
+    boolean showDialogInternal() {
+        if (!mAttachedToWindow) {
+            return false;
         }
 
-        refreshDrawableState();
+        DialogFragment f = MediaRouteDialogPresenter.showDialogFragment(getActivity(),
+                mRouteTypes, mExtendedSettingsClickListener);
+        return f != null;
+    }
+
+    private Activity getActivity() {
+        // Gross way of unwrapping the Activity so we can get the FragmentManager
+        Context context = getContext();
+        while (context instanceof ContextWrapper) {
+            if (context instanceof Activity) {
+                return (Activity)context;
+            }
+            context = ((ContextWrapper)context).getBaseContext();
+        }
+        throw new IllegalStateException("The MediaRouteButton's Context is not an Activity.");
+    }
+
+    /**
+     * Sets whether to enable showing a toast with the content descriptor of the
+     * button when the button is long pressed.
+     */
+    void setCheatSheetEnabled(boolean enable) {
+        mCheatSheetEnabled = enable;
     }
 
     @Override
@@ -120,29 +187,7 @@
         if (!handled) {
             playSoundEffect(SoundEffectConstants.CLICK);
         }
-
-        if (mToggleMode) {
-            if (mRemoteActive) {
-                mRouter.selectRouteInt(mRouteTypes, mRouter.getDefaultRoute());
-            } else {
-                final int N = mRouter.getRouteCount();
-                for (int i = 0; i < N; i++) {
-                    final RouteInfo route = mRouter.getRouteAt(i);
-                    if ((route.getSupportedTypes() & mRouteTypes) != 0 &&
-                            route != mRouter.getDefaultRoute()) {
-                        mRouter.selectRouteInt(mRouteTypes, route);
-                    }
-                }
-            }
-        } else {
-            showDialog();
-        }
-
-        return handled;
-    }
-
-    void setCheatSheetEnabled(boolean enable) {
-        mCheatSheetEnabled = enable;
+        return showDialogInternal() || handled;
     }
 
     @Override
@@ -183,85 +228,9 @@
         }
         cheatSheet.show();
         performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-
         return true;
     }
 
-    public void setRouteTypes(int types) {
-        if (types == mRouteTypes) {
-            // Already registered; nothing to do.
-            return;
-        }
-
-        if (mAttachedToWindow && mRouteTypes != 0) {
-            mRouter.removeCallback(mRouterCallback);
-        }
-
-        mRouteTypes = types;
-
-        if (mAttachedToWindow) {
-            updateRouteInfo();
-            mRouter.addCallback(types, mRouterCallback);
-        }
-    }
-
-    private void updateRouteInfo() {
-        updateRemoteIndicator();
-        updateRouteCount();
-    }
-
-    public int getRouteTypes() {
-        return mRouteTypes;
-    }
-
-    void updateRemoteIndicator() {
-        final RouteInfo selected = mRouter.getSelectedRoute(mRouteTypes);
-        final boolean isRemote = selected != mRouter.getDefaultRoute();
-        final boolean isConnecting = selected != null &&
-                selected.getStatusCode() == RouteInfo.STATUS_CONNECTING;
-
-        boolean needsRefresh = false;
-        if (mRemoteActive != isRemote) {
-            mRemoteActive = isRemote;
-            needsRefresh = true;
-        }
-        if (mIsConnecting != isConnecting) {
-            mIsConnecting = isConnecting;
-            needsRefresh = true;
-        }
-
-        if (needsRefresh) {
-            refreshDrawableState();
-        }
-    }
-
-    void updateRouteCount() {
-        final int N = mRouter.getRouteCount();
-        int count = 0;
-        boolean hasVideoRoutes = false;
-        for (int i = 0; i < N; i++) {
-            final RouteInfo route = mRouter.getRouteAt(i);
-            final int routeTypes = route.getSupportedTypes();
-            if ((routeTypes & mRouteTypes) != 0) {
-                if (route instanceof RouteGroup) {
-                    count += ((RouteGroup) route).getRouteCount();
-                } else {
-                    count++;
-                }
-                if ((routeTypes & MediaRouter.ROUTE_TYPE_LIVE_VIDEO) != 0) {
-                    hasVideoRoutes = true;
-                }
-            }
-        }
-
-        setEnabled(count != 0);
-
-        // Only allow toggling if we have more than just user routes.
-        // Don't toggle if we support video routes, we may have to let the dialog scan.
-        mToggleMode = count == 2 && (mRouteTypes & MediaRouter.ROUTE_TYPE_LIVE_AUDIO) != 0 &&
-                !hasVideoRoutes;
-    }
-
     @Override
     protected int[] onCreateDrawableState(int extraSpace) {
         final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
@@ -289,6 +258,21 @@
         }
     }
 
+    private void setRemoteIndicatorDrawable(Drawable d) {
+        if (mRemoteIndicator != null) {
+            mRemoteIndicator.setCallback(null);
+            unscheduleDrawable(mRemoteIndicator);
+        }
+        mRemoteIndicator = d;
+        if (d != null) {
+            d.setCallback(this);
+            d.setState(getDrawableState());
+            d.setVisible(getVisibility() == VISIBLE, false);
+        }
+
+        refreshDrawableState();
+    }
+
     @Override
     protected boolean verifyDrawable(Drawable who) {
         return super.verifyDrawable(who) || who == mRemoteIndicator;
@@ -297,12 +281,16 @@
     @Override
     public void jumpDrawablesToCurrentState() {
         super.jumpDrawablesToCurrentState();
-        if (mRemoteIndicator != null) mRemoteIndicator.jumpToCurrentState();
+
+        if (mRemoteIndicator != null) {
+            mRemoteIndicator.jumpToCurrentState();
+        }
     }
 
     @Override
     public void setVisibility(int visibility) {
         super.setVisibility(visibility);
+
         if (mRemoteIndicator != null) {
             mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
         }
@@ -311,19 +299,22 @@
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
+
         mAttachedToWindow = true;
         if (mRouteTypes != 0) {
-            mRouter.addCallback(mRouteTypes, mRouterCallback);
-            updateRouteInfo();
+            mRouter.addCallback(mRouteTypes, mCallback,
+                    MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
         }
+        refreshRoute();
     }
 
     @Override
     public void onDetachedFromWindow() {
-        if (mRouteTypes != 0) {
-            mRouter.removeCallback(mRouterCallback);
-        }
         mAttachedToWindow = false;
+        if (mRouteTypes != 0) {
+            mRouter.removeCallback(mCallback);
+        }
+
         super.onDetachedFromWindow();
     }
 
@@ -386,93 +377,71 @@
         final int drawLeft = left + (right - left - drawWidth) / 2;
         final int drawTop = top + (bottom - top - drawHeight) / 2;
 
-        mRemoteIndicator.setBounds(drawLeft, drawTop, drawLeft + drawWidth, drawTop + drawHeight);
+        mRemoteIndicator.setBounds(drawLeft, drawTop,
+                drawLeft + drawWidth, drawTop + drawHeight);
         mRemoteIndicator.draw(canvas);
     }
 
-    public void setExtendedSettingsClickListener(OnClickListener listener) {
-        mExtendedSettingsClickListener = listener;
-        if (mDialogFragment != null) {
-            mDialogFragment.setExtendedSettingsClickListener(listener);
-        }
-    }
+    private void refreshRoute() {
+        if (mAttachedToWindow) {
+            final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
+            final boolean isRemote = !route.isDefault() && route.matchesTypes(mRouteTypes);
+            final boolean isConnecting = isRemote && route.isConnecting();
 
-    /**
-     * Asynchronously show the route chooser dialog.
-     * This will attach a {@link DialogFragment} to the containing Activity.
-     */
-    public void showDialog() {
-        final FragmentManager fm = getActivity().getFragmentManager();
-        if (mDialogFragment == null) {
-            // See if one is already attached to this activity.
-            mDialogFragment = (MediaRouteChooserDialogFragment) fm.findFragmentByTag(
-                    MediaRouteChooserDialogFragment.FRAGMENT_TAG);
-        }
-        if (mDialogFragment != null) {
-            Log.w(TAG, "showDialog(): Already showing!");
-            return;
-        }
-
-        mDialogFragment = new MediaRouteChooserDialogFragment();
-        mDialogFragment.setExtendedSettingsClickListener(mExtendedSettingsClickListener);
-        mDialogFragment.setLauncherListener(new MediaRouteChooserDialogFragment.LauncherListener() {
-            @Override
-            public void onDetached(MediaRouteChooserDialogFragment detachedFragment) {
-                mDialogFragment = null;
+            boolean needsRefresh = false;
+            if (mRemoteActive != isRemote) {
+                mRemoteActive = isRemote;
+                needsRefresh = true;
             }
-        });
-        mDialogFragment.setRouteTypes(mRouteTypes);
-        mDialogFragment.show(fm, MediaRouteChooserDialogFragment.FRAGMENT_TAG);
+            if (mIsConnecting != isConnecting) {
+                mIsConnecting = isConnecting;
+                needsRefresh = true;
+            }
+
+            if (needsRefresh) {
+                refreshDrawableState();
+            }
+
+            setEnabled(mRouter.isRouteAvailable(mRouteTypes,
+                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
+        }
     }
 
-    private Activity getActivity() {
-        // Gross way of unwrapping the Activity so we can get the FragmentManager
-        Context context = getContext();
-        while (context instanceof ContextWrapper && !(context instanceof Activity)) {
-            context = ((ContextWrapper) context).getBaseContext();
-        }
-        if (!(context instanceof Activity)) {
-            throw new IllegalStateException("The MediaRouteButton's Context is not an Activity.");
-        }
-
-        return (Activity) context;
-    }
-
-    private class MediaRouteCallback extends MediaRouter.SimpleCallback {
-        @Override
-        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
-            updateRemoteIndicator();
-        }
-
-        @Override
-        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
-            updateRemoteIndicator();
-        }
-
-        @Override
-        public void onRouteChanged(MediaRouter router, RouteInfo info) {
-            updateRemoteIndicator();
-        }
-
+    private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
         @Override
         public void onRouteAdded(MediaRouter router, RouteInfo info) {
-            updateRouteCount();
+            refreshRoute();
         }
 
         @Override
         public void onRouteRemoved(MediaRouter router, RouteInfo info) {
-            updateRouteCount();
+            refreshRoute();
+        }
+
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo info) {
+            refreshRoute();
+        }
+
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+            refreshRoute();
+        }
+
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+            refreshRoute();
         }
 
         @Override
         public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
                 int index) {
-            updateRouteCount();
+            refreshRoute();
         }
 
         @Override
         public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
-            updateRouteCount();
+            refreshRoute();
         }
     }
 }
diff --git a/core/java/android/content/SyncInfo.java b/core/java/android/content/SyncInfo.java
index 0284882..cffc653 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -55,6 +55,14 @@
     }
 
     /** @hide */
+    public SyncInfo(SyncInfo other) {
+        this.authorityId = other.authorityId;
+        this.account = new Account(other.account.name, other.account.type);
+        this.authority = other.authority;
+        this.startTime = other.startTime;
+    }
+
+    /** @hide */
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 267fb2a..20002ad 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -53,6 +53,7 @@
  *  {@hide}
  */
 interface IPackageManager {
+    boolean isPackageAvailable(String packageName, int userId);
     PackageInfo getPackageInfo(String packageName, int flags, int userId);
     int getPackageUid(String packageName, int userId);
     int[] getPackageGids(String packageName);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 17d13e5..e6da288 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -282,6 +282,10 @@
                 || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
     }
 
+    public static boolean isAvailable(PackageUserState state) {
+        return checkUseInstalledOrBlocked(0, state);
+    }
+
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
             int gids[], int flags, long firstInstallTime, long lastUpdateTime,
             HashSet<String> grantedPermissions, PackageUserState state, int userId) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4fe2c4d..a38beec 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -334,6 +334,27 @@
 
     /**
      * <p>
+     * If set to 1, the HAL will always split result
+     * metadata for a single capture into multiple buffers,
+     * returned using multiple process_capture_result calls.
+     * </p>
+     * <p>
+     * Does not need to be listed in static
+     * metadata. Support for partial results will be reworked in
+     * future versions of camera service. This quirk will stop
+     * working at that point; DO NOT USE without careful
+     * consideration of future support.
+     * </p>
+     *
+     * <b>Optional</b> - This value may be null on some devices.
+     *
+     * @hide
+     */
+    public static final Key<Byte> QUIRKS_USE_PARTIAL_RESULT =
+            new Key<Byte>("android.quirks.usePartialResult", byte.class);
+
+    /**
+     * <p>
      * How many output streams can be allocated at
      * the same time for each type of stream
      * </p>
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 7095e4d..9e8d7d1 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -631,6 +631,36 @@
         }
 
         /**
+         * This method is called when some results from an image capture are
+         * available.
+         *
+         * <p>The result provided here will contain some subset of the fields of
+         * a full result. Multiple onCapturePartial calls may happen per
+         * capture; a given result field will only be present in one partial
+         * capture at most. The final onCaptureCompleted call will always
+         * contain all the fields, whether onCapturePartial was called or
+         * not.</p>
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param camera The CameraDevice sending the callback.
+         * @param request The request that was given to the CameraDevice
+         * @param result The partial output metadata from the capture, which
+         * includes a subset of the CaptureResult fields.
+         *
+         * @see #capture
+         * @see #captureBurst
+         * @see #setRepeatingRequest
+         * @see #setRepeatingBurst
+         *
+         * @hide
+         */
+        public void onCapturePartial(CameraDevice camera,
+                CaptureRequest request, CaptureResult result) {
+            // default empty implementation
+        }
+
+        /**
          * This method is called when an image capture has completed and the
          * result metadata is available.
          *
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index dbd0457..535b963 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -591,6 +591,32 @@
 
     /**
      * <p>
+     * Whether a result given to the framework is the
+     * final one for the capture, or only a partial that contains a
+     * subset of the full set of dynamic metadata
+     * values.
+     * </p>
+     * <p>
+     * The entries in the result metadata buffers for a
+     * single capture may not overlap, except for this entry. The
+     * FINAL buffers must retain FIFO ordering relative to the
+     * requests that generate them, so the FINAL buffer for frame 3 must
+     * always be sent to the framework after the FINAL buffer for frame 2, and
+     * before the FINAL buffer for frame 4. PARTIAL buffers may be returned
+     * in any order relative to other frames, but all PARTIAL buffers for a given
+     * capture must arrive before the FINAL buffer for that capture. This entry may
+     * only be used by the HAL if quirks.usePartialResult is set to 1.
+     * </p>
+     *
+     * <b>Optional</b> - This value may be null on some devices.
+     *
+     * @hide
+     */
+    public static final Key<Boolean> QUIRKS_PARTIAL_RESULT =
+            new Key<Boolean>("android.quirks.partialResult", boolean.class);
+
+    /**
+     * <p>
      * A frame counter set by the framework. This value monotonically
      * increases with every new result (that is, each new result has a unique
      * frameCount value).
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index c428a17..40586f0 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -279,6 +279,10 @@
             checkIfCameraClosed();
             int requestId;
 
+            if (repeating) {
+                stopRepeating();
+            }
+
             try {
                 requestId = mRemoteDevice.submitRequest(request, repeating);
             } catch (CameraRuntimeException e) {
@@ -293,10 +297,6 @@
             }
 
             if (repeating) {
-                // Queue for deletion after in-flight requests finish
-                if (mRepeatingRequestId != REQUEST_ID_NONE) {
-                    mRepeatingRequestIdDeletedList.add(mRepeatingRequestId);
-                }
                 mRepeatingRequestId = requestId;
             }
 
@@ -577,6 +577,9 @@
             }
             final CaptureListenerHolder holder;
 
+            Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT);
+            boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial);
+
             synchronized (mLock) {
                 // TODO: move this whole map into this class to make it more testable,
                 //        exposing the methods necessary like subscribeToRequest, unsubscribe..
@@ -585,7 +588,7 @@
                 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
 
                 // Clean up listener once we no longer expect to see it.
-                if (holder != null && !holder.isRepeating()) {
+                if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
                     CameraDevice.this.mCaptureListenerMap.remove(requestId);
                 }
 
@@ -595,7 +598,7 @@
                 // If we received a result for a repeating request and have
                 // prior repeating requests queued for deletion, remove those
                 // requests from mCaptureListenerMap.
-                if (holder != null && holder.isRepeating()
+                if (holder != null && holder.isRepeating() && !quirkIsPartialResult
                         && mRepeatingRequestIdDeletedList.size() > 0) {
                     Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
                     while (iter.hasNext()) {
@@ -619,8 +622,25 @@
             final CaptureRequest request = holder.getRequest();
             final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId);
 
-            holder.getHandler().post(
-                new Runnable() {
+            Runnable resultDispatch = null;
+
+            // Either send a partial result or the final capture completed result
+            if (quirkIsPartialResult) {
+                // Partial result
+                resultDispatch = new Runnable() {
+                    @Override
+                    public void run() {
+                        if (!CameraDevice.this.isClosed()){
+                            holder.getListener().onCapturePartial(
+                                CameraDevice.this,
+                                request,
+                                resultAsCapture);
+                        }
+                    }
+                };
+            } else {
+                // Final capture result
+                resultDispatch = new Runnable() {
                     @Override
                     public void run() {
                         if (!CameraDevice.this.isClosed()){
@@ -630,7 +650,10 @@
                                 resultAsCapture);
                         }
                     }
-                });
+                };
+            }
+
+            holder.getHandler().post(resultDispatch);
         }
 
     }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index f12be5f..d5208d9 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -299,6 +299,10 @@
     /**
      * Initiates a fresh scan of availble Wifi displays.
      * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+     * <p>
+     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
+     * </p>
+     *
      * @hide
      */
     public void scanWifiDisplays() {
@@ -312,8 +316,7 @@
      * Automatically remembers the display after a successful connection, if not
      * already remembered.
      * </p><p>
-     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} to connect
-     * to unknown displays.  No permissions are required to connect to already known displays.
+     * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}.
      * </p>
      *
      * @param deviceAddress The MAC address of the device to which we should connect.
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 78ac75f..010e527 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -139,6 +139,17 @@
         return false;
     }
 
+    public boolean isValid() {
+        if (!TextUtils.isEmpty(mPacFileUrl)) return true;
+        try {
+            Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort),
+                    mExclusionList == null ? "" : mExclusionList);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+        return true;
+    }
+
     public java.net.Proxy makeProxy() {
         java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
         if (mHost != null) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 7ae8ca8..9ada6e6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -106,6 +106,11 @@
     public static final int FOREGROUND_ACTIVITY = 10;
 
     /**
+     * A constant indicating a wifi batched scan is active
+     */
+    public static final int WIFI_BATCHED_SCAN = 11;
+
+    /**
      * Include all of the data in the stats, including previously saved data.
      */
     public static final int STATS_SINCE_CHARGED = 0;
@@ -270,6 +275,8 @@
         public abstract void noteFullWifiLockReleasedLocked();
         public abstract void noteWifiScanStartedLocked();
         public abstract void noteWifiScanStoppedLocked();
+        public abstract void noteWifiBatchedScanStartedLocked(int csph);
+        public abstract void noteWifiBatchedScanStoppedLocked();
         public abstract void noteWifiMulticastEnabledLocked();
         public abstract void noteWifiMulticastDisabledLocked();
         public abstract void noteAudioTurnedOnLocked();
@@ -281,6 +288,7 @@
         public abstract long getWifiRunningTime(long batteryRealtime, int which);
         public abstract long getFullWifiLockTime(long batteryRealtime, int which);
         public abstract long getWifiScanTime(long batteryRealtime, int which);
+        public abstract long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which);
         public abstract long getWifiMulticastTime(long batteryRealtime,
                                                   int which);
         public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
@@ -288,6 +296,8 @@
         public abstract Timer getForegroundActivityTimer();
         public abstract Timer getVibratorOnTimer();
 
+        public static final int NUM_WIFI_BATCHED_SCAN_BINS = 5;
+
         /**
          * Note that these must match the constants in android.os.PowerManager.
          * Also, if the user activity types change, the BatteryStatsImpl.VERSION must
@@ -2081,9 +2091,11 @@
                                         TimeUtils.formatDuration(ew.usedTime, pw);
                                         pw.print(" over ");
                                         TimeUtils.formatDuration(ew.overTime, pw);
-                                        pw.print(" (");
-                                        pw.print((ew.usedTime*100)/ew.overTime);
-                                        pw.println("%)");
+                                        if (ew.overTime != 0) {
+                                            pw.print(" (");
+                                            pw.print((ew.usedTime*100)/ew.overTime);
+                                            pw.println("%)");
+                                        }
                             }
                         }
                         uidActivity = true;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 37a8102..f7d1eb7 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1069,11 +1069,11 @@
      * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>;
      *          greater than 0 if this Preference sorts after <var>another</var>.
      */
+    @Override
     public int compareTo(Preference another) {
-        if (mOrder != DEFAULT_ORDER
-                || (mOrder == DEFAULT_ORDER && another.mOrder != DEFAULT_ORDER)) {
+        if (mOrder != another.mOrder) {
             // Do order comparison
-            return mOrder - another.mOrder; 
+            return mOrder - another.mOrder;
         } else if (mTitle == another.mTitle) {
             // If titles are null or share same object comparison
             return 0;
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index ed9264a..7ddfa87 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -521,7 +521,9 @@
         int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);
         int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);
 
-        if (savedInstanceState != null) {
+        // Restore from headers only if they are supported which
+        // is in multi-pane mode.
+        if (savedInstanceState != null && !mSinglePane) {
             // We are restarting from a previous saved state; used that to
             // initialize, instead of starting fresh.
             ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG);
@@ -573,14 +575,12 @@
             // Single pane, showing just a prefs fragment.
             findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
             mPrefsContainer.setVisibility(View.VISIBLE);
-            CharSequence initialTitleStr = null;
-            CharSequence initialShortTitleStr = null;
             if (initialTitle != 0) {
-                initialTitleStr = getText(initialTitle);
-                initialShortTitleStr = initialShortTitle != 0
+                CharSequence initialTitleStr = getText(initialTitle);
+                CharSequence initialShortTitleStr = initialShortTitle != 0
                         ? getText(initialShortTitle) : null;
+                showBreadCrumbs(initialTitleStr, initialShortTitleStr);
             }
-            showBreadCrumbs(initialTitleStr, initialShortTitleStr);
         } else if (mHeaders.size() > 0) {
             setListAdapter(new HeaderAdapter(this, mHeaders));
             if (!mSinglePane) {
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 9e811a6..1f59bef 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -141,15 +141,36 @@
      * or {@link LayoutResultCallback#onLayoutCancelled()} if layout was
      * cancelled in a response to a cancellation request via the passed in
      * {@link CancellationSignal}. Note that you <strong>must</strong> call one of
-     * the methods of the given callback for this method to be considered complete.
+     * the methods of the given callback for this method to be considered complete
+     * which is you will not receive any calls to this adapter until the current
+     * layout operation is complete by invoking a method on the callback instance.
+     * The callback methods can be invoked from an arbitrary thread.
      * </p>
      * <p>
+     * One of the arguments passed to this method is a {@link CancellationSignal}
+     * which is used to propagate requests from the system to your application for
+     * canceling the current layout operation. For example, a cancellation may be
+     * requested if the user changes a print option that may affect layout while
+     * you are performing a layout operation. In such a case the system will make
+     * an attempt to cancel the current layout as another one will have to be performed.
+     * Typically, you should register a cancellation callback in the cancellation
+     * signal. The cancellation callback <strong>will not</strong> be made on the
+     * main thread and can be registered as follows:
+     * </p>
+     * <pre>
+     * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+     *     &#064;Override
+     *     public void onCancel() {
+     *         // Cancel layout
+     *     }
+     * });
+     * </pre>
+     * <p>
      * <strong>Note:</strong> If the content is large and a layout will be
      * performed, it is a good practice to schedule the work on a dedicated
      * thread and register an observer in the provided {@link
      * CancellationSignal} upon invocation of which you should stop the
-     * layout. The cancellation callback <strong>will not</strong> be made on
-     * the main thread.
+     * layout.
      * </p>
      *
      * @param oldAttributes The old print attributes.
@@ -177,14 +198,36 @@
      * CharSequence)}, if an error occurred; or {@link WriteResultCallback#onWriteCancelled()},
      * if writing was cancelled in a response to a cancellation request via the passed
      * in {@link CancellationSignal}. Note that you <strong>must</strong> call one of
-     * the methods of the given callback for this method to be considered complete.
+     * the methods of the given callback for this method to be considered complete which
+     * is you will not receive any calls to this adapter until the current write
+     * operation is complete by invoking a method on the callback instance. The callback
+     * methods can be invoked from an arbitrary thread.
      * </p>
      * <p>
+     * One of the arguments passed to this method is a {@link CancellationSignal}
+     * which is used to propagate requests from the system to your application for
+     * canceling the current write operation. For example, a cancellation may be
+     * requested if the user changes a print option that may affect layout while
+     * you are performing a write operation. In such a case the system will make
+     * an attempt to cancel the current write as a layout will have to be performed
+     * which then may be followed by a write. Typically, you should register a
+     * cancellation callback in the cancellation signal. The cancellation callback
+     * <strong>will not</strong> be made on the main thread and can be registered
+     * as follows:
+     * </p>
+     * <pre>
+     * cancellationSignal.setOnCancelListener(new OnCancelListener() {
+     *     &#064;Override
+     *     public void onCancel() {
+     *         // Cancel write
+     *     }
+     * });
+     * </pre>
+     * <p>
      * <strong>Note:</strong> If the printed content is large, it is a good
      * practice to schedule writing it on a dedicated thread and register an
      * observer in the provided {@link CancellationSignal} upon invocation of
-     * which you should stop writing. The cancellation callback will not be
-     * made on the main thread.
+     * which you should stop writing.
      * </p>
      *
      * @param pages The pages whose content to print - non-overlapping in ascending order.
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index d6d56bb..d1bb8fd 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -860,6 +860,11 @@
                 }
                 final ILayoutResultCallback callback;
                 synchronized (mLock) {
+                    if (mDestroyed) {
+                        Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+                                + "finish the printing activity before print completion?");
+                        return;
+                    }
                     callback = mCallback;
                     clearLocked();
                 }
@@ -876,6 +881,11 @@
             public void onLayoutFailed(CharSequence error) {
                 final ILayoutResultCallback callback;
                 synchronized (mLock) {
+                    if (mDestroyed) {
+                        Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+                                + "finish the printing activity before print completion?");
+                        return;
+                    }
                     callback = mCallback;
                     clearLocked();
                 }
@@ -891,6 +901,11 @@
             @Override
             public void onLayoutCancelled() {
                 synchronized (mLock) {
+                    if (mDestroyed) {
+                        Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+                                + "finish the printing activity before print completion?");
+                        return;
+                    }
                     clearLocked();
                 }
             }
@@ -918,6 +933,11 @@
             public void onWriteFinished(PageRange[] pages) {
                 final IWriteResultCallback callback;
                 synchronized (mLock) {
+                    if (mDestroyed) {
+                        Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+                                + "finish the printing activity before print completion?");
+                        return;
+                    }
                     callback = mCallback;
                     clearLocked();
                 }
@@ -940,6 +960,11 @@
             public void onWriteFailed(CharSequence error) {
                 final IWriteResultCallback callback;
                 synchronized (mLock) {
+                    if (mDestroyed) {
+                        Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+                                + "finish the printing activity before print completion?");
+                        return;
+                    }
                     callback = mCallback;
                     clearLocked();
                 }
@@ -955,6 +980,11 @@
             @Override
             public void onWriteCancelled() {
                 synchronized (mLock) {
+                    if (mDestroyed) {
+                        Log.e(LOG_TAG, "PrintDocumentAdapter is destroyed. Did you "
+                                + "finish the printing activity before print completion?");
+                        return;
+                    }
                     clearLocked();
                 }
             }
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index cc81be5..49816f8 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -62,7 +62,8 @@
  *            android:authorities="com.example.mycloudprovider"
  *            android:exported="true"
  *            android:grantUriPermissions="true"
- *            android:permission="android.permission.MANAGE_DOCUMENTS"&gt;
+ *            android:permission="android.permission.MANAGE_DOCUMENTS"
+ *            android:enabled="@bool/isAtLeastKitKat"&gt;
  *            &lt;intent-filter&gt;
  *                &lt;action android:name="android.content.action.DOCUMENTS_PROVIDER" /&gt;
  *            &lt;/intent-filter&gt;
@@ -252,7 +253,8 @@
      * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that
      * you are still fetching additional data. Then, when the network data is
      * available, you can send a change notification to trigger a requery and
-     * return the complete contents.
+     * return the complete contents. To return a Cursor with extras, you need to
+     * extend and override {@link Cursor#getExtras()}.
      * <p>
      * To support change notifications, you must
      * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant
@@ -362,7 +364,7 @@
      * @param documentId the document to return.
      * @param mode the mode to open with, such as 'r', 'w', or 'rw'.
      * @param signal used by the caller to signal if the request should be
-     *            cancelled.
+     *            cancelled. May be null.
      * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler,
      *      OnCloseListener)
      * @see ParcelFileDescriptor#createReliablePipe()
@@ -386,7 +388,7 @@
      * @param documentId the document to return.
      * @param sizeHint hint of the optimal thumbnail dimensions.
      * @param signal used by the caller to signal if the request should be
-     *            cancelled.
+     *            cancelled. May be null.
      * @see Document#FLAG_SUPPORTS_THUMBNAIL
      */
     @SuppressWarnings("unused")
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index 6d066d6..c596388 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -46,9 +46,9 @@
      * of text being given.  Currently supported classes are:
      * {@link #TYPE_CLASS_TEXT}, {@link #TYPE_CLASS_NUMBER},
      * {@link #TYPE_CLASS_PHONE}, {@link #TYPE_CLASS_DATETIME}.
-     * If the class is not one you
+     * <p>IME authors: If the class is not one you
      * understand, assume {@link #TYPE_CLASS_TEXT} with NO variation
-     * or flags.
+     * or flags.<p>
      */
     public static final int TYPE_MASK_CLASS = 0x0000000f;
     
@@ -69,7 +69,10 @@
      * This should be interpreted to mean that the target input connection
      * is not rich, it can not process and show things like candidate text nor
      * retrieve the current text, so the input method will need to run in a
-     * limited "generate key events" mode.
+     * limited "generate key events" mode, if it supports it. Note that some
+     * input methods may not support it, for example a voice-based input
+     * method will likely not be able to generate key events even if this
+     * flag is set.
      */
     public static final int TYPE_NULL = 0x00000000;
     
@@ -94,48 +97,70 @@
      * Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters.  Overrides
      * {@link #TYPE_TEXT_FLAG_CAP_WORDS} and
      * {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}.  This value is explicitly defined
-     * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}.
+     * to be the same as {@link TextUtils#CAP_MODE_CHARACTERS}. Of course,
+     * this only affects languages where there are upper-case and lower-case letters.
      */
     public static final int TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000;
     
     /**
-     * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of
-     * all words.  Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}.  This
+     * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of
+     * every word.  Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}.  This
      * value is explicitly defined
-     * to be the same as {@link TextUtils#CAP_MODE_WORDS}.
+     * to be the same as {@link TextUtils#CAP_MODE_WORDS}. Of course,
+     * this only affects languages where there are upper-case and lower-case letters.
      */
     public static final int TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000;
     
     /**
-     * Flag for {@link #TYPE_CLASS_TEXT}: capitalize first character of
+     * Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of
      * each sentence.  This value is explicitly defined
-     * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}.
+     * to be the same as {@link TextUtils#CAP_MODE_SENTENCES}. For example
+     * in English it means to capitalize after a period and a space (note that other
+     * languages may have different characters for period, or not use spaces,
+     * or use different grammatical rules). Of course,
+     * this only affects languages where there are upper-case and lower-case letters.
      */
     public static final int TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000;
     
     /**
      * Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form
-     * text that should have auto-correction applied to it.
+     * text that should have auto-correction applied to it. Without this flag,
+     * the IME will not try to correct typos. You should always set this flag
+     * unless you really expect users to type non-words in this field, for
+     * example to choose a name for a character in a game.
+     * Contrast this with {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE} and
+     * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}:
+     * {@code TYPE_TEXT_FLAG_AUTO_CORRECT} means that the IME will try to
+     * auto-correct typos as the user is typing, but does not define whether
+     * the IME offers an interface to show suggestions.
      */
     public static final int TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000;
     
     /**
-     * Flag for {@link #TYPE_CLASS_TEXT}: the text editor is performing
-     * auto-completion of the text being entered based on its own semantics,
-     * which it will present to the user as they type.  This generally means
-     * that the input method should not be showing candidates itself, but can
-     * expect for the editor to supply its own completions/candidates from
+     * Flag for {@link #TYPE_CLASS_TEXT}: the text editor (which means
+     * the application) is performing auto-completion of the text being entered
+     * based on its own semantics, which it will present to the user as they type.
+     * This generally means that the input method should not be showing
+     * candidates itself, but can expect the editor to supply its own
+     * completions/candidates from
      * {@link android.view.inputmethod.InputMethodSession#displayCompletions
      * InputMethodSession.displayCompletions()} as a result of the editor calling
      * {@link android.view.inputmethod.InputMethodManager#displayCompletions
      * InputMethodManager.displayCompletions()}.
+     * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and
+     * {@link #TYPE_TEXT_FLAG_NO_SUGGESTIONS}:
+     * {@code TYPE_TEXT_FLAG_AUTO_COMPLETE} means the editor should show an
+     * interface for displaying suggestions, but instead of supplying its own
+     * it will rely on the Editor to pass completions/corrections.
      */
     public static final int TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000;
     
     /**
      * Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be
      * entered into the field.  If this flag is not set, the text field 
-     * will be constrained to a single line.
+     * will be constrained to a single line. The IME may also choose not to
+     * display an enter key when this flag is not set, as there should be no
+     * need to create new lines.
      */
     public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000;
     
@@ -152,6 +177,16 @@
      * do not contain words from the language and do not benefit from any
      * dictionary-based completions or corrections. It overrides the
      * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set.
+     * Please avoid using this unless you are certain this is what you want.
+     * Many input methods need suggestions to work well, for example the ones
+     * based on gesture typing. Consider clearing
+     * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} instead if you just do not
+     * want the IME to correct typos.
+     * Note the contrast with {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} and
+     * {@link #TYPE_TEXT_FLAG_AUTO_COMPLETE}:
+     * {@code TYPE_TEXT_FLAG_NO_SUGGESTIONS} means the IME should never
+     * show an interface to display suggestions. Most IMEs will also take this to
+     * mean they should not try to auto-correct what the user is typing.
      */
     public static final int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000;
 
@@ -224,7 +259,9 @@
     
     /**
      * Variation of {@link #TYPE_CLASS_TEXT}: entering text for phonetic
-     * pronunciation, such as a phonetic name field in contacts.
+     * pronunciation, such as a phonetic name field in contacts. This is mostly
+     * useful for languages where one spelling may have several phonetic
+     * readings, like Japanese.
      */
     public static final int TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0;
     
@@ -255,12 +292,13 @@
     // ----------------------------------------------------------------------
     
     /**
-     * Class for numeric text.  This class supports the following flag:
+     * Class for numeric text.  This class supports the following flags:
      * {@link #TYPE_NUMBER_FLAG_SIGNED} and
      * {@link #TYPE_NUMBER_FLAG_DECIMAL}.  It also supports the following
      * variations: {@link #TYPE_NUMBER_VARIATION_NORMAL} and
-     * {@link #TYPE_NUMBER_VARIATION_PASSWORD}.  If you do not recognize
-     * the variation, normal should be assumed.
+     * {@link #TYPE_NUMBER_VARIATION_PASSWORD}.
+     * <p>IME authors: If you do not recognize
+     * the variation, normal should be assumed.</p>
      */
     public static final int TYPE_CLASS_NUMBER = 0x00000002;
     
@@ -318,7 +356,7 @@
      * following variations:
      * {@link #TYPE_DATETIME_VARIATION_NORMAL}
      * {@link #TYPE_DATETIME_VARIATION_DATE}, and
-     * {@link #TYPE_DATETIME_VARIATION_TIME},.
+     * {@link #TYPE_DATETIME_VARIATION_TIME}.
      */
     public static final int TYPE_CLASS_DATETIME = 0x00000004;
     
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 354ea66..7d310a2 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -643,6 +643,15 @@
                 || uid == 0;
     }
 
+    /**
+     * Returns true if the display is a public presentation display.
+     * @hide
+     */
+    public boolean isPublicPresentation() {
+        return (mFlags & (Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION)) ==
+                Display.FLAG_PRESENTATION;
+    }
+
     private void updateDisplayInfoLocked() {
         // Note: The display manager caches display info objects on our behalf.
         DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 1b76cb1..c92a104 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -78,7 +78,8 @@
     void addWindowToken(IBinder token, int type);
     void removeWindowToken(IBinder token);
     void addAppToken(int addPos, IApplicationToken token, int groupId, int stackId,
-            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId);
+            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
+            int configChanges);
     void setAppGroupId(IBinder token, int groupId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index f36c78f..42a58a8 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -323,6 +323,10 @@
                 mInProgress = false;
                 mInitialSpan = 0;
                 mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
+            } else if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS && streamComplete) {
+                mInProgress = false;
+                mInitialSpan = 0;
+                mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
             }
 
             if (streamComplete) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index aa2b0d4..06f8e8c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18,7 +18,6 @@
 
 import android.content.ClipData;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -3102,7 +3101,15 @@
      */
     private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
 
-    private boolean mUseBackgroundPadding = false;
+    /**
+     * Cache if a left padding has been defined
+     */
+    private boolean mLeftPaddingDefined = false;
+
+    /**
+     * Cache if a right padding has been defined
+     */
+    private boolean mRightPaddingDefined = false;
 
     /**
      * @hide
@@ -3532,10 +3539,10 @@
         int overScrollMode = mOverScrollMode;
         boolean initializeScrollbars = false;
 
-        boolean leftPaddingDefined = false;
-        boolean rightPaddingDefined = false;
         boolean startPaddingDefined = false;
         boolean endPaddingDefined = false;
+        boolean leftPaddingDefined = false;
+        boolean rightPaddingDefined = false;
 
         final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
 
@@ -3867,6 +3874,11 @@
             setBackground(background);
         }
 
+        // setBackground above will record that padding is currently provided by the background.
+        // If we have padding specified via xml, record that here instead and use it.
+        mLeftPaddingDefined = leftPaddingDefined;
+        mRightPaddingDefined = rightPaddingDefined;
+
         if (padding >= 0) {
             leftPadding = padding;
             topPadding = padding;
@@ -3884,11 +3896,11 @@
             // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial
             // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if
             // defined.
-            if (!leftPaddingDefined && startPaddingDefined) {
+            if (!mLeftPaddingDefined && startPaddingDefined) {
                 leftPadding = startPadding;
             }
             mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial;
-            if (!rightPaddingDefined && endPaddingDefined) {
+            if (!mRightPaddingDefined && endPaddingDefined) {
                 rightPadding = endPadding;
             }
             mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial;
@@ -3900,10 +3912,10 @@
             // defined.
             final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined;
 
-            if (leftPaddingDefined && !hasRelativePadding) {
+            if (mLeftPaddingDefined && !hasRelativePadding) {
                 mUserPaddingLeftInitial = leftPadding;
             }
-            if (rightPaddingDefined && !hasRelativePadding) {
+            if (mRightPaddingDefined && !hasRelativePadding) {
                 mUserPaddingRightInitial = rightPadding;
             }
         }
@@ -12347,15 +12359,19 @@
             // If start / end padding are defined, they will be resolved (hence overriding) to
             // left / right or right / left depending on the resolved layout direction.
             // If start / end padding are not defined, use the left / right ones.
-            if (mBackground != null && mUseBackgroundPadding) {
+            if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) {
                 Rect padding = sThreadLocal.get();
                 if (padding == null) {
                     padding = new Rect();
                     sThreadLocal.set(padding);
                 }
                 mBackground.getPadding(padding);
-                mUserPaddingLeftInitial = padding.left;
-                mUserPaddingRightInitial = padding.right;
+                if (!mLeftPaddingDefined) {
+                    mUserPaddingLeftInitial = padding.left;
+                }
+                if (!mRightPaddingDefined) {
+                    mUserPaddingRightInitial = padding.right;
+                }
             }
             switch (resolvedLayoutDirection) {
                 case LAYOUT_DIRECTION_RTL:
@@ -15352,9 +15368,8 @@
                         mUserPaddingRightInitial = padding.right;
                         internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
                 }
-                mUseBackgroundPadding = true;
-            } else {
-                mUseBackgroundPadding = false;
+                mLeftPaddingDefined = false;
+                mRightPaddingDefined = false;
             }
 
             // Compare the minimum sizes of the old Drawable and the new.  If there isn't an old or
@@ -15380,8 +15395,6 @@
             /* Remove the background */
             mBackground = null;
 
-            mUseBackgroundPadding = false;
-
             if ((mPrivateFlags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0) {
                 /*
                  * This view ONLY drew the background before and we're removing
@@ -15453,7 +15466,8 @@
         mUserPaddingLeftInitial = left;
         mUserPaddingRightInitial = right;
 
-        mUseBackgroundPadding = false;
+        mLeftPaddingDefined = true;
+        mRightPaddingDefined = true;
 
         internalSetPadding(left, top, right, bottom);
     }
@@ -15540,8 +15554,8 @@
 
         mUserPaddingStart = start;
         mUserPaddingEnd = end;
-
-        mUseBackgroundPadding = false;
+        mLeftPaddingDefined = true;
+        mRightPaddingDefined = true;
 
         switch(getLayoutDirection()) {
             case LAYOUT_DIRECTION_RTL:
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 5146567..d4e005b 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -70,14 +70,14 @@
     /**
      * Bits of {@link #IME_MASK_ACTION}: the action key performs a "search"
      * operation, taking the user to the results of searching for the text
-     * the have typed (in whatever context is appropriate).
+     * they have typed (in whatever context is appropriate).
      */
     public static final int IME_ACTION_SEARCH = 0x00000003;
     
     /**
      * Bits of {@link #IME_MASK_ACTION}: the action key performs a "send"
      * operation, delivering the text to its target.  This is typically used
-     * when composing a message.
+     * when composing a message in IM or SMS where sending is immediate.
      */
     public static final int IME_ACTION_SEND = 0x00000004;
     
@@ -89,22 +89,31 @@
     
     /**
      * Bits of {@link #IME_MASK_ACTION}: the action key performs a "done"
-     * operation, typically meaning the IME will be closed.
+     * operation, typically meaning there is nothing more to input and the
+     * IME will be closed.
      */
     public static final int IME_ACTION_DONE = 0x00000006;
     
     /**
      * Bits of {@link #IME_MASK_ACTION}: Like {@link #IME_ACTION_NEXT}, but
      * for moving to the previous field.  This will normally not be used to
-     * specify an action (since it precludes {@link #IME_ACTION_NEXT}, but
+     * specify an action (since it precludes {@link #IME_ACTION_NEXT}), but
      * can be returned to the app if it sets {@link #IME_FLAG_NAVIGATE_PREVIOUS}.
      */
     public static final int IME_ACTION_PREVIOUS = 0x00000007;
 
     /**
      * Flag of {@link #imeOptions}: used to request that the IME never go
-     * into fullscreen mode.  Applications need to be aware that the flag is not
-     * a guarantee, and not all IMEs will respect it.
+     * into fullscreen mode.
+     * By default, IMEs may go into full screen mode when they think
+     * it's appropriate, for example on small screens in landscape
+     * orientation where displaying a software keyboard may occlude
+     * such a large portion of the screen that the remaining part is
+     * too small to meaningfully display the application UI.
+     * If this flag is set, compliant IMEs will never go into full screen mode,
+     * and always leave some space to display the application UI.
+     * Applications need to be aware that the flag is not a guarantee, and
+     * some IMEs may ignore it.
      */
     public static final int IME_FLAG_NO_FULLSCREEN = 0x2000000;
 
@@ -136,50 +145,56 @@
      * Flag of {@link #imeOptions}: used to specify that the IME does not need
      * to show its extracted text UI.  For input methods that may be fullscreen,
      * often when in landscape mode, this allows them to be smaller and let part
-     * of the application be shown behind.  Though there will likely be limited
-     * access to the application available from the user, it can make the
-     * experience of a (mostly) fullscreen IME less jarring.  Note that when
-     * this flag is specified the IME may <em>not</em> be set up to be able
-     * to display text, so it should only be used in situations where this is
-     * not needed.
+     * of the application be shown behind, through transparent UI parts in the
+     * fullscreen IME. The part of the UI visible to the user may not be responsive
+     * to touch because the IME will receive touch events, which may confuse the
+     * user; use {@link #IME_FLAG_NO_FULLSCREEN} instead for a better experience.
+     * Using this flag is discouraged and it may become deprecated in the future.
+     * Its meaning is unclear in some situations and it may not work appropriately
+     * on older versions of the platform.
      */
     public static final int IME_FLAG_NO_EXTRACT_UI = 0x10000000;
     
     /**
-     * Flag of {@link #imeOptions}: used in conjunction with
-     * {@link #IME_MASK_ACTION}, this indicates that the action should not
-     * be available as an accessory button when the input method is full-screen.
-     * Note that by setting this flag, there can be cases where the action
-     * is simply never available to the user.  Setting this generally means
-     * that you think showing text being edited is more important than the
-     * action you have supplied. 
+     * Flag of {@link #imeOptions}: used in conjunction with one of the actions
+     * masked by {@link #IME_MASK_ACTION}, this indicates that the action
+     * should not be available as an accessory button on the right of the extracted
+     * text when the input method is full-screen. Note that by setting this flag,
+     * there can be cases where the action is simply never available to the
+     * user. Setting this generally means that you think that in fullscreen mode,
+     * where there is little space to show the text, it's not worth taking some
+     * screen real estate to display the action and it should be used instead
+     * to show more text.
      */
     public static final int IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000;
     
     /**
-     * Flag of {@link #imeOptions}: used in conjunction with
-     * {@link #IME_MASK_ACTION}, this indicates that the action should not
-     * be available in-line as a replacement for "enter" key.  Typically this is
-     * because the action has such a significant impact or is not recoverable
-     * enough that accidentally hitting it should be avoided, such as sending
-     * a message.  Note that {@link android.widget.TextView} will automatically set this
-     * flag for you on multi-line text views.
+     * Flag of {@link #imeOptions}: used in conjunction with one of the actions
+     * masked by {@link #IME_MASK_ACTION}. If this flag is not set, IMEs will
+     * normally replace the "enter" key with the action supplied. This flag
+     * indicates that the action should not be available in-line as a replacement
+     * for the "enter" key. Typically this is because the action has such a
+     * significant impact or is not recoverable enough that accidentally hitting
+     * it should be avoided, such as sending a message. Note that
+     * {@link android.widget.TextView} will automatically set this flag for you
+     * on multi-line text views.
      */
     public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;
 
     /**
-     * Flag of {@link #imeOptions}: used to request that the IME is capable of
+     * Flag of {@link #imeOptions}: used to request an IME that is capable of
      * inputting ASCII characters.  The intention of this flag is to ensure that
-     * the user can type Roman alphabet characters in a {@link android.widget.TextView}
-     * used for, typically, account ID or password input.  It is expected that IMEs
-     * normally are able to input ASCII even without being told so (such IMEs
-     * already respect this flag in a sense), but there could be some cases they
-     * aren't when, for instance, only non-ASCII input languagaes like Arabic,
-     * Greek, Hebrew, Russian are enabled in the IME.  Applications need to be
-     * aware that the flag is not a guarantee, and not all IMEs will respect it.
+     * the user can type Roman alphabet characters in a {@link android.widget.TextView}.
+     * It is typically used for an account ID or password input. A lot of the time,
+     * IMEs are already able to input ASCII even without being told so (such IMEs
+     * already respect this flag in a sense), but there are cases when this is not
+     * the default. For instance, users of languages using a different script like
+     * Arabic, Greek, Hebrew or Russian typically have a keyboard that can't
+     * input ASCII characters by default. Applications need to be
+     * aware that the flag is not a guarantee, and some IMEs may not respect it.
      * However, it is strongly recommended for IME authors to respect this flag
-     * especially when their IME could end up with a state that has only non-ASCII
-     * input languages enabled.
+     * especially when their IME could end up with a state where only languages
+     * using non-ASCII are enabled.
      */
     public static final int IME_FLAG_FORCE_ASCII = 0x80000000;
 
@@ -209,8 +224,13 @@
     
     /**
      * In some cases an IME may be able to display an arbitrary label for
-     * a command the user can perform, which you can specify here.  You can
-     * not count on this being used.
+     * a command the user can perform, which you can specify here. This is
+     * typically used as the label for the action to use in-line as a replacement
+     * for the "enter" key (see {@link #actionId}). Remember the key where
+     * this will be displayed is typically very small, and there are significant
+     * localization challenges to make this fit in all supported languages. Also
+     * you can not count absolutely on this being used, as some IMEs may
+     * ignore this.
      */
     public CharSequence actionLabel = null;
     
@@ -224,13 +244,17 @@
     
     /**
      * The text offset of the start of the selection at the time editing
-     * began; -1 if not known.
+     * began; -1 if not known. Keep in mind some IMEs may not be able
+     * to give their full feature set without knowing the cursor position;
+     * avoid passing -1 here if you can.
      */
     public int initialSelStart = -1;
     
     /**
      * The text offset of the end of the selection at the time editing
-     * began; -1 if not known.
+     * began; -1 if not known. Keep in mind some IMEs may not be able
+     * to give their full feature set without knowing the cursor position;
+     * avoid passing -1 here if you can.
      */
     public int initialSelEnd = -1;
     
@@ -280,7 +304,7 @@
      * Any extra data to supply to the input method.  This is for extended
      * communication with specific input methods; the name fields in the
      * bundle should be scoped (such as "com.mydomain.im.SOME_FIELD") so
-     * that they don't conflict with others.  This field is can be
+     * that they don't conflict with others.  This field can be
      * filled in from the {@link android.R.attr#editorExtras}
      * attribute of a TextView.
      */
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 59330ca..3537aec 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -142,7 +142,11 @@
      * conditions in implementing this call. An IME can make a change
      * to the text and use this method right away; you need to make
      * sure the returned value is consistent with the result of the
-     * latest edits.
+     * latest edits. Also, you may return less than n characters if performance
+     * dictates so, but keep in mind IMEs are relying on this for many
+     * functions: you should not, for example, limit the returned value to
+     * the current line, and specifically do not return 0 characters unless
+     * the cursor is really at the start of the text.</p>
      *
      * @param n The expected length of the text.
      * @param flags Supplies additional options controlling how the text is
@@ -176,7 +180,11 @@
      * conditions in implementing this call. An IME can make a change
      * to the text and use this method right away; you need to make
      * sure the returned value is consistent with the result of the
-     * latest edits.</p>
+     * latest edits. Also, you may return less than n characters if performance
+     * dictates so, but keep in mind IMEs are relying on this for many
+     * functions: you should not, for example, limit the returned value to
+     * the current line, and specifically do not return 0 characters unless
+     * the cursor is really at the end of the text.</p>
      *
      * @param n The expected length of the text.
      * @param flags Supplies additional options controlling how the text is
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 40f95ce..2ab3024 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -534,6 +534,13 @@
     private static int hashCodeInternal(String locale, String mode, String extraValue,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
             boolean isAsciiCapable) {
+        // CAVEAT: Must revisit how to compute needsToCalculateCompatibleHashCode when a new
+        // attribute is added in order to avoid enabled subtypes being unexpectedly disabled.
+        final boolean needsToCalculateCompatibleHashCode = !isAsciiCapable;
+        if (needsToCalculateCompatibleHashCode) {
+            return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
+                    overridesImplicitlyEnabledSubtype});
+        }
         return Arrays.hashCode(new Object[] {locale, mode, extraValue, isAuxiliary,
                 overridesImplicitlyEnabledSubtype, isAsciiCapable});
     }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 9e35a23..7daf798 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -710,6 +710,7 @@
             }
             d.setLevel(mLevel);
             d.setLayoutDirection(getLayoutDirection());
+            d.setVisible(getVisibility() == VISIBLE, true);
             mDrawableWidth = d.getIntrinsicWidth();
             mDrawableHeight = d.getIntrinsicHeight();
             applyColorMod();
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index fbdf318..d57b739 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -56,7 +56,17 @@
  * can load images from various sources (such as resources or content
  * providers), takes care of computing its measurement from the video so that
  * it can be used in any layout manager, and provides various display options
- * such as scaling and tinting.
+ * such as scaling and tinting.<p>
+ *
+ * <em>Note: VideoView does not retain its full state when going into the
+ * background.</em>  In particular, it does not restore the current play state,
+ * play position, selected tracks, or any subtitle tracks added via
+ * {@link #addSubtitleSource addSubtitleSource()}.  Applications should
+ * save and restore these on their own in
+ * {@link android.app.Activity#onSaveInstanceState} and
+ * {@link android.app.Activity#onRestoreInstanceState}.<p>
+ * Also note that the audio session id (from {@link #getAudioSessionId}) may
+ * change from its previously returned value when the VideoView is restored.
  */
 public class VideoView extends SurfaceView
         implements MediaPlayerControl, SubtitleController.Anchor {
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 525517c..43c4b49 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -68,6 +68,8 @@
     void noteFullWifiLockReleasedFromSource(in WorkSource ws);
     void noteWifiScanStartedFromSource(in WorkSource ws);
     void noteWifiScanStoppedFromSource(in WorkSource ws);
+    void noteWifiBatchedScanStartedFromSource(in WorkSource ws, int csph);
+    void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
     void noteWifiMulticastEnabledFromSource(in WorkSource ws);
     void noteWifiMulticastDisabledFromSource(in WorkSource ws);
     void noteNetworkInterfaceType(String iface, int type);
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialog.java b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
new file mode 100644
index 0000000..47d2a9c
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2013 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.android.internal.app;
+
+import com.android.internal.R;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.Comparator;
+
+/**
+ * This class implements the route chooser dialog for {@link MediaRouter}.
+ * <p>
+ * This dialog allows the user to choose a route that matches a given selector.
+ * </p>
+ *
+ * @see MediaRouteButton
+ * @see MediaRouteActionProvider
+ *
+ * TODO: Move this back into the API, as in the support library media router.
+ */
+public class MediaRouteChooserDialog extends Dialog {
+    private final MediaRouter mRouter;
+    private final MediaRouterCallback mCallback;
+
+    private int mRouteTypes;
+    private View.OnClickListener mExtendedSettingsClickListener;
+    private RouteAdapter mAdapter;
+    private ListView mListView;
+    private Button mExtendedSettingsButton;
+    private boolean mAttachedToWindow;
+
+    public MediaRouteChooserDialog(Context context, int theme) {
+        super(context, theme);
+
+        mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        mCallback = new MediaRouterCallback();
+    }
+
+    /**
+     * Gets the media route types for filtering the routes that the user can
+     * select using the media route chooser dialog.
+     *
+     * @return The route types.
+     */
+    public int getRouteTypes() {
+        return mRouteTypes;
+    }
+
+    /**
+     * Sets the types of routes that will be shown in the media route chooser dialog
+     * launched by this button.
+     *
+     * @param types The route types to match.
+     */
+    public void setRouteTypes(int types) {
+        if (mRouteTypes != types) {
+            mRouteTypes = types;
+
+            if (mAttachedToWindow) {
+                mRouter.removeCallback(mCallback);
+                mRouter.addCallback(types, mCallback,
+                        MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+            }
+
+            refreshRoutes();
+        }
+    }
+
+    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
+        if (listener != mExtendedSettingsClickListener) {
+            mExtendedSettingsClickListener = listener;
+            updateExtendedSettingsButton();
+        }
+    }
+
+    /**
+     * Returns true if the route should be included in the list.
+     * <p>
+     * The default implementation returns true for enabled non-default routes that
+     * match the route types.  Subclasses can override this method to filter routes
+     * differently.
+     * </p>
+     *
+     * @param route The route to consider, never null.
+     * @return True if the route should be included in the chooser dialog.
+     */
+    public boolean onFilterRoute(MediaRouter.RouteInfo route) {
+        return !route.isDefault() && route.isEnabled() && route.matchesTypes(mRouteTypes);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
+
+        setContentView(R.layout.media_route_chooser_dialog);
+        setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
+                ? R.string.media_route_chooser_title_for_remote_display
+                : R.string.media_route_chooser_title);
+
+        // Must be called after setContentView.
+        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
+                R.drawable.ic_media_route_off_holo_dark);
+
+        mAdapter = new RouteAdapter(getContext());
+        mListView = (ListView)findViewById(R.id.media_route_list);
+        mListView.setAdapter(mAdapter);
+        mListView.setOnItemClickListener(mAdapter);
+        mListView.setEmptyView(findViewById(android.R.id.empty));
+
+        mExtendedSettingsButton = (Button)findViewById(R.id.media_route_extended_settings_button);
+        updateExtendedSettingsButton();
+    }
+
+    private void updateExtendedSettingsButton() {
+        if (mExtendedSettingsButton != null) {
+            mExtendedSettingsButton.setOnClickListener(mExtendedSettingsClickListener);
+            mExtendedSettingsButton.setVisibility(
+                    mExtendedSettingsClickListener != null ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        mAttachedToWindow = true;
+        mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+        refreshRoutes();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        mAttachedToWindow = false;
+        mRouter.removeCallback(mCallback);
+
+        super.onDetachedFromWindow();
+    }
+
+    /**
+     * Refreshes the list of routes that are shown in the chooser dialog.
+     */
+    public void refreshRoutes() {
+        if (mAttachedToWindow) {
+            mAdapter.update();
+        }
+    }
+
+    private final class RouteAdapter extends ArrayAdapter<MediaRouter.RouteInfo>
+            implements ListView.OnItemClickListener {
+        private final LayoutInflater mInflater;
+
+        public RouteAdapter(Context context) {
+            super(context, 0);
+            mInflater = LayoutInflater.from(context);
+        }
+
+        public void update() {
+            clear();
+            final int count = mRouter.getRouteCount();
+            for (int i = 0; i < count; i++) {
+                MediaRouter.RouteInfo route = mRouter.getRouteAt(i);
+                if (onFilterRoute(route)) {
+                    add(route);
+                }
+            }
+            sort(RouteComparator.sInstance);
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return getItem(position).isEnabled();
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View view = convertView;
+            if (view == null) {
+                view = mInflater.inflate(R.layout.media_route_list_item, parent, false);
+            }
+            MediaRouter.RouteInfo route = getItem(position);
+            TextView text1 = (TextView)view.findViewById(android.R.id.text1);
+            TextView text2 = (TextView)view.findViewById(android.R.id.text2);
+            text1.setText(route.getName());
+            CharSequence description = route.getDescription();
+            if (TextUtils.isEmpty(description)) {
+                text2.setVisibility(View.GONE);
+                text2.setText("");
+            } else {
+                text2.setVisibility(View.VISIBLE);
+                text2.setText(description);
+            }
+            view.setEnabled(route.isEnabled());
+            return view;
+        }
+
+        @Override
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+            MediaRouter.RouteInfo route = getItem(position);
+            if (route.isEnabled()) {
+                route.select();
+                dismiss();
+            }
+        }
+    }
+
+    private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
+        @Override
+        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
+            refreshRoutes();
+        }
+
+        @Override
+        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
+            refreshRoutes();
+        }
+
+        @Override
+        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
+            refreshRoutes();
+        }
+
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+            dismiss();
+        }
+    }
+
+    private static final class RouteComparator implements Comparator<MediaRouter.RouteInfo> {
+        public static final RouteComparator sInstance = new RouteComparator();
+
+        @Override
+        public int compare(MediaRouter.RouteInfo lhs, MediaRouter.RouteInfo rhs) {
+            return lhs.getName().toString().compareTo(rhs.getName().toString());
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
index e300021..ae362af 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -16,675 +16,86 @@
 
 package com.android.internal.app;
 
-import com.android.internal.R;
-
-import android.app.Activity;
 import android.app.Dialog;
 import android.app.DialogFragment;
-import android.app.MediaRouteActionProvider;
-import android.app.MediaRouteButton;
 import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
-import android.media.MediaRouter;
-import android.media.MediaRouter.RouteCategory;
-import android.media.MediaRouter.RouteGroup;
-import android.media.MediaRouter.RouteInfo;
 import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.CheckBox;
-import android.widget.Checkable;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.SeekBar;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import android.view.View.OnClickListener;
 
 /**
- * This class implements the route chooser dialog for {@link MediaRouter}.
+ * Media route chooser dialog fragment.
+ * <p>
+ * Creates a {@link MediaRouteChooserDialog}.  The application may subclass
+ * this dialog fragment to customize the media route chooser dialog.
+ * </p>
  *
- * @see MediaRouteButton
- * @see MediaRouteActionProvider
+ * TODO: Move this back into the API, as in the support library media router.
  */
 public class MediaRouteChooserDialogFragment extends DialogFragment {
-    private static final String TAG = "MediaRouteChooserDialogFragment";
-    public static final String FRAGMENT_TAG = "android:MediaRouteChooserDialogFragment";
+    private final String ARGUMENT_ROUTE_TYPES = "routeTypes";
 
-    private static final int[] ITEM_LAYOUTS = new int[] {
-        R.layout.media_route_list_item_top_header,
-        R.layout.media_route_list_item_section_header,
-        R.layout.media_route_list_item,
-        R.layout.media_route_list_item_checkable,
-        R.layout.media_route_list_item_collapse_group
-    };
+    private View.OnClickListener mExtendedSettingsClickListener;
 
-    MediaRouter mRouter;
-    private int mRouteTypes;
-
-    private LayoutInflater mInflater;
-    private LauncherListener mLauncherListener;
-    private View.OnClickListener mExtendedSettingsListener;
-    private RouteAdapter mAdapter;
-    private ListView mListView;
-    private SeekBar mVolumeSlider;
-    private ImageView mVolumeIcon;
-
-    final RouteComparator mComparator = new RouteComparator();
-    final MediaRouterCallback mCallback = new MediaRouterCallback();
-    private boolean mIgnoreSliderVolumeChanges;
-    private boolean mIgnoreCallbackVolumeChanges;
-
+    /**
+     * Creates a media route chooser dialog fragment.
+     * <p>
+     * All subclasses of this class must also possess a default constructor.
+     * </p>
+     */
     public MediaRouteChooserDialogFragment() {
-        setStyle(STYLE_NO_TITLE, R.style.Theme_DeviceDefault_Dialog);
+        setCancelable(true);
+        setStyle(STYLE_NORMAL, android.R.style.Theme_DeviceDefault_Dialog);
     }
 
-    public void setLauncherListener(LauncherListener listener) {
-        mLauncherListener = listener;
-    }
-
-    @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
-        mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE);
-        mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
-    }
-
-    @Override
-    public void onDetach() {
-        super.onDetach();
-        if (mLauncherListener != null) {
-            mLauncherListener.onDetached(this);
-        }
-        if (mAdapter != null) {
-            mAdapter = null;
-        }
-        mInflater = null;
-        mRouter.removeCallback(mCallback);
-        mRouter = null;
-    }
-
-    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
-        mExtendedSettingsListener = listener;
+    public int getRouteTypes() {
+        Bundle args = getArguments();
+        return args != null ? args.getInt(ARGUMENT_ROUTE_TYPES) : 0;
     }
 
     public void setRouteTypes(int types) {
-        mRouteTypes = types;
-    }
-
-    void updateVolume() {
-        if (mRouter == null) return;
-
-        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
-        mVolumeIcon.setImageResource(selectedRoute == null ||
-                selectedRoute.getPlaybackType() == RouteInfo.PLAYBACK_TYPE_LOCAL ?
-                R.drawable.ic_audio_vol : R.drawable.ic_media_route_on_holo_dark);
-
-        mIgnoreSliderVolumeChanges = true;
-
-        if (selectedRoute == null ||
-                selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_FIXED) {
-            // Disable the slider and show it at max volume.
-            mVolumeSlider.setMax(1);
-            mVolumeSlider.setProgress(1);
-            mVolumeSlider.setEnabled(false);
-        } else {
-            mVolumeSlider.setEnabled(true);
-            mVolumeSlider.setMax(selectedRoute.getVolumeMax());
-            mVolumeSlider.setProgress(selectedRoute.getVolume());
-        }
-
-        mIgnoreSliderVolumeChanges = false;
-    }
-
-    void changeVolume(int newValue) {
-        if (mIgnoreSliderVolumeChanges) return;
-
-        final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
-        if (selectedRoute != null &&
-                selectedRoute.getVolumeHandling() == RouteInfo.PLAYBACK_VOLUME_VARIABLE) {
-            final int maxVolume = selectedRoute.getVolumeMax();
-            newValue = Math.max(0, Math.min(newValue, maxVolume));
-            selectedRoute.requestSetVolume(newValue);
-        }
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        mInflater = inflater;
-        final View layout = inflater.inflate(R.layout.media_route_chooser_layout, container, false);
-
-        mVolumeIcon = (ImageView) layout.findViewById(R.id.volume_icon);
-        mVolumeSlider = (SeekBar) layout.findViewById(R.id.volume_slider);
-        updateVolume();
-        mVolumeSlider.setOnSeekBarChangeListener(new VolumeSliderChangeListener());
-
-        if (mExtendedSettingsListener != null) {
-            final View extendedSettingsButton = layout.findViewById(R.id.extended_settings);
-            extendedSettingsButton.setVisibility(View.VISIBLE);
-            extendedSettingsButton.setOnClickListener(mExtendedSettingsListener);
-        }
-
-        final ListView list = (ListView) layout.findViewById(R.id.list);
-        list.setItemsCanFocus(true);
-        list.setAdapter(mAdapter = new RouteAdapter());
-        list.setOnItemClickListener(mAdapter);
-
-        mListView = list;
-
-        mAdapter.scrollToSelectedItem();
-
-        return layout;
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        return new RouteChooserDialog(getActivity(), getTheme());
-    }
-
-    private static class ViewHolder {
-        public TextView text1;
-        public TextView text2;
-        public ImageView icon;
-        public ImageButton expandGroupButton;
-        public RouteAdapter.ExpandGroupListener expandGroupListener;
-        public int position;
-        public CheckBox check;
-    }
-
-    private class RouteAdapter extends BaseAdapter implements ListView.OnItemClickListener {
-        private static final int VIEW_TOP_HEADER = 0;
-        private static final int VIEW_SECTION_HEADER = 1;
-        private static final int VIEW_ROUTE = 2;
-        private static final int VIEW_GROUPING_ROUTE = 3;
-        private static final int VIEW_GROUPING_DONE = 4;
-
-        private int mSelectedItemPosition = -1;
-        private final ArrayList<Object> mItems = new ArrayList<Object>();
-
-        private RouteCategory mCategoryEditingGroups;
-        private RouteGroup mEditingGroup;
-
-        // Temporary lists for manipulation
-        private final ArrayList<RouteInfo> mCatRouteList = new ArrayList<RouteInfo>();
-        private final ArrayList<RouteInfo> mSortRouteList = new ArrayList<RouteInfo>();
-
-        private boolean mIgnoreUpdates;
-
-        RouteAdapter() {
-            update();
-        }
-
-        void update() {
-            /*
-             * This is kind of wacky, but our data sets are going to be
-             * fairly small on average. Ideally we should be able to do some of this stuff
-             * in-place instead.
-             *
-             * Basic idea: each entry in mItems represents an item in the list for quick access.
-             * Entries can be a RouteCategory (section header), a RouteInfo with a category of
-             * mCategoryEditingGroups (a flattened RouteInfo pulled out of its group, allowing
-             * the user to change the group),
-             */
-            if (mIgnoreUpdates) return;
-
-            mItems.clear();
-
-            final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
-            mSelectedItemPosition = -1;
-
-            List<RouteInfo> routes;
-            final int catCount = mRouter.getCategoryCount();
-            for (int i = 0; i < catCount; i++) {
-                final RouteCategory cat = mRouter.getCategoryAt(i);
-                routes = cat.getRoutes(mCatRouteList);
-
-                if (!cat.isSystem()) {
-                    mItems.add(cat);
-                }
-
-                if (cat == mCategoryEditingGroups) {
-                    addGroupEditingCategoryRoutes(routes);
-                } else {
-                    addSelectableRoutes(selectedRoute, routes);
-                }
-
-                routes.clear();
+        if (types != getRouteTypes()) {
+            Bundle args = getArguments();
+            if (args == null) {
+                args = new Bundle();
             }
+            args.putInt(ARGUMENT_ROUTE_TYPES, types);
+            setArguments(args);
 
-            notifyDataSetChanged();
-            if (mListView != null && mSelectedItemPosition >= 0) {
-                mListView.setItemChecked(mSelectedItemPosition, true);
-            }
-        }
-
-        void scrollToEditingGroup() {
-            if (mCategoryEditingGroups == null || mListView == null) return;
-
-            int pos = 0;
-            int bound = 0;
-            final int itemCount = mItems.size();
-            for (int i = 0; i < itemCount; i++) {
-                final Object item = mItems.get(i);
-                if (item != null && item == mCategoryEditingGroups) {
-                    bound = i;
-                }
-                if (item == null) {
-                    pos = i;
-                    break; // this is always below the category header; we can stop here.
-                }
-            }
-
-            mListView.smoothScrollToPosition(pos, bound);
-        }
-
-        void scrollToSelectedItem() {
-            if (mListView == null || mSelectedItemPosition < 0) return;
-
-            mListView.smoothScrollToPosition(mSelectedItemPosition);
-        }
-
-        void addSelectableRoutes(RouteInfo selectedRoute, List<RouteInfo> from) {
-            final int routeCount = from.size();
-            for (int j = 0; j < routeCount; j++) {
-                final RouteInfo info = from.get(j);
-                if (info == selectedRoute) {
-                    mSelectedItemPosition = mItems.size();
-                }
-                mItems.add(info);
-            }
-        }
-
-        void addGroupEditingCategoryRoutes(List<RouteInfo> from) {
-            // Unpack groups and flatten for presentation
-            // mSortRouteList will always be empty here.
-            final int topCount = from.size();
-            for (int i = 0; i < topCount; i++) {
-                final RouteInfo route = from.get(i);
-                final RouteGroup group = route.getGroup();
-                if (group == route) {
-                    // This is a group, unpack it.
-                    final int groupCount = group.getRouteCount();
-                    for (int j = 0; j < groupCount; j++) {
-                        final RouteInfo innerRoute = group.getRouteAt(j);
-                        mSortRouteList.add(innerRoute);
-                    }
-                } else {
-                    mSortRouteList.add(route);
-                }
-            }
-            // Sort by name. This will keep the route positions relatively stable even though they
-            // will be repeatedly added and removed.
-            Collections.sort(mSortRouteList, mComparator);
-
-            mItems.addAll(mSortRouteList);
-            mSortRouteList.clear();
-
-            mItems.add(null); // Sentinel reserving space for the "done" button.
-        }
-
-        @Override
-        public int getCount() {
-            return mItems.size();
-        }
-
-        @Override
-        public int getViewTypeCount() {
-            return 5;
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            final Object item = getItem(position);
-            if (item instanceof RouteCategory) {
-                return position == 0 ? VIEW_TOP_HEADER : VIEW_SECTION_HEADER;
-            } else if (item == null) {
-                return VIEW_GROUPING_DONE;
-            } else {
-                final RouteInfo info = (RouteInfo) item;
-                if (info.getCategory() == mCategoryEditingGroups) {
-                    return VIEW_GROUPING_ROUTE;
-                }
-                return VIEW_ROUTE;
-            }
-        }
-
-        @Override
-        public boolean areAllItemsEnabled() {
-            return false;
-        }
-
-        @Override
-        public boolean isEnabled(int position) {
-            switch (getItemViewType(position)) {
-                case VIEW_ROUTE:
-                    return ((RouteInfo) mItems.get(position)).isEnabled();
-                case VIEW_GROUPING_ROUTE:
-                case VIEW_GROUPING_DONE:
-                    return true;
-                default:
-                    return false;
-            }
-        }
-
-        @Override
-        public Object getItem(int position) {
-            return mItems.get(position);
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            final int viewType = getItemViewType(position);
-
-            ViewHolder holder;
-            if (convertView == null) {
-                convertView = mInflater.inflate(ITEM_LAYOUTS[viewType], parent, false);
-                holder = new ViewHolder();
-                holder.position = position;
-                holder.text1 = (TextView) convertView.findViewById(R.id.text1);
-                holder.text2 = (TextView) convertView.findViewById(R.id.text2);
-                holder.icon = (ImageView) convertView.findViewById(R.id.icon);
-                holder.check = (CheckBox) convertView.findViewById(R.id.check);
-                holder.expandGroupButton = (ImageButton) convertView.findViewById(
-                        R.id.expand_button);
-                if (holder.expandGroupButton != null) {
-                    holder.expandGroupListener = new ExpandGroupListener();
-                    holder.expandGroupButton.setOnClickListener(holder.expandGroupListener);
-                }
-
-                final View fview = convertView;
-                final ListView list = (ListView) parent;
-                final ViewHolder fholder = holder;
-                convertView.setOnClickListener(new View.OnClickListener() {
-                    @Override public void onClick(View v) {
-                        list.performItemClick(fview, fholder.position, 0);
-                    }
-                });
-                convertView.setTag(holder);
-            } else {
-                holder = (ViewHolder) convertView.getTag();
-                holder.position = position;
-            }
-
-            switch (viewType) {
-                case VIEW_ROUTE:
-                case VIEW_GROUPING_ROUTE:
-                    bindItemView(position, holder);
-                    break;
-                case VIEW_SECTION_HEADER:
-                case VIEW_TOP_HEADER:
-                    bindHeaderView(position, holder);
-                    break;
-            }
-
-            convertView.setActivated(position == mSelectedItemPosition);
-            convertView.setEnabled(isEnabled(position));
-
-            return convertView;
-        }
-
-        void bindItemView(int position, ViewHolder holder) {
-            RouteInfo info = (RouteInfo) mItems.get(position);
-            holder.text1.setText(info.getName(getActivity()));
-            final CharSequence status = info.getStatus();
-            if (TextUtils.isEmpty(status)) {
-                holder.text2.setVisibility(View.GONE);
-            } else {
-                holder.text2.setVisibility(View.VISIBLE);
-                holder.text2.setText(status);
-            }
-            Drawable icon = info.getIconDrawable();
-            if (icon != null) {
-                // Make sure we have a fresh drawable where it doesn't matter if we mutate it
-                icon = icon.getConstantState().newDrawable(getResources());
-            }
-            holder.icon.setImageDrawable(icon);
-            holder.icon.setVisibility(icon != null ? View.VISIBLE : View.GONE);
-
-            RouteCategory cat = info.getCategory();
-            boolean canGroup = false;
-            if (cat == mCategoryEditingGroups) {
-                RouteGroup group = info.getGroup();
-                holder.check.setEnabled(group.getRouteCount() > 1);
-                holder.check.setChecked(group == mEditingGroup);
-            } else {
-                if (cat.isGroupable()) {
-                    final RouteGroup group = (RouteGroup) info;
-                    canGroup = group.getRouteCount() > 1 ||
-                            getItemViewType(position - 1) == VIEW_ROUTE ||
-                            (position < getCount() - 1 &&
-                                    getItemViewType(position + 1) == VIEW_ROUTE);
-                }
-            }
-
-            if (holder.expandGroupButton != null) {
-                holder.expandGroupButton.setVisibility(canGroup ? View.VISIBLE : View.GONE);
-                holder.expandGroupListener.position = position;
-            }
-        }
-
-        void bindHeaderView(int position, ViewHolder holder) {
-            RouteCategory cat = (RouteCategory) mItems.get(position);
-            holder.text1.setText(cat.getName(getActivity()));
-        }
-
-        @Override
-        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-            final int type = getItemViewType(position);
-            if (type == VIEW_SECTION_HEADER || type == VIEW_TOP_HEADER) {
-                return;
-            } else if (type == VIEW_GROUPING_DONE) {
-                finishGrouping();
-                return;
-            } else {
-                final Object item = getItem(position);
-                if (!(item instanceof RouteInfo)) {
-                    // Oops. Stale event running around? Skip it.
-                    return;
-                }
-
-                final RouteInfo route = (RouteInfo) item;
-                if (type == VIEW_ROUTE) {
-                    mRouter.selectRouteInt(mRouteTypes, route);
-                    dismiss();
-                } else if (type == VIEW_GROUPING_ROUTE) {
-                    final Checkable c = (Checkable) view;
-                    final boolean wasChecked = c.isChecked();
-
-                    mIgnoreUpdates = true;
-                    RouteGroup oldGroup = route.getGroup();
-                    if (!wasChecked && oldGroup != mEditingGroup) {
-                        // Assumption: in a groupable category oldGroup will never be null.
-                        if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
-                            // Old group was selected but is now empty. Select the group
-                            // we're manipulating since that's where the last route went.
-                            mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
-                        }
-                        oldGroup.removeRoute(route);
-                        mEditingGroup.addRoute(route);
-                        c.setChecked(true);
-                    } else if (wasChecked && mEditingGroup.getRouteCount() > 1) {
-                        mEditingGroup.removeRoute(route);
-
-                        // In a groupable category this will add
-                        // the route into its own new group.
-                        mRouter.addRouteInt(route);
-                    }
-                    mIgnoreUpdates = false;
-                    update();
-                }
-            }
-        }
-
-        boolean isGrouping() {
-            return mCategoryEditingGroups != null;
-        }
-
-        void finishGrouping() {
-            mCategoryEditingGroups = null;
-            mEditingGroup = null;
-            getDialog().setCanceledOnTouchOutside(true);
-            update();
-            scrollToSelectedItem();
-        }
-
-        class ExpandGroupListener implements View.OnClickListener {
-            int position;
-
-            @Override
-            public void onClick(View v) {
-                // Assumption: this is only available for the user to click if we're presenting
-                // a groupable category, where every top-level route in the category is a group.
-                final RouteGroup group = (RouteGroup) getItem(position);
-                mEditingGroup = group;
-                mCategoryEditingGroups = group.getCategory();
-                getDialog().setCanceledOnTouchOutside(false);
-                mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
-                update();
-                scrollToEditingGroup();
+            MediaRouteChooserDialog dialog = (MediaRouteChooserDialog)getDialog();
+            if (dialog != null) {
+                dialog.setRouteTypes(types);
             }
         }
     }
 
-    class MediaRouterCallback extends MediaRouter.Callback {
-        @Override
-        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
-            mAdapter.update();
-            updateVolume();
-        }
+    public void setExtendedSettingsClickListener(View.OnClickListener listener) {
+        if (listener != mExtendedSettingsClickListener) {
+            mExtendedSettingsClickListener = listener;
 
-        @Override
-        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
-            mAdapter.update();
-        }
-
-        @Override
-        public void onRouteAdded(MediaRouter router, RouteInfo info) {
-            mAdapter.update();
-        }
-
-        @Override
-        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
-            if (info == mAdapter.mEditingGroup) {
-                mAdapter.finishGrouping();
-            }
-            mAdapter.update();
-        }
-
-        @Override
-        public void onRouteChanged(MediaRouter router, RouteInfo info) {
-            mAdapter.notifyDataSetChanged();
-        }
-
-        @Override
-        public void onRouteGrouped(MediaRouter router, RouteInfo info,
-                RouteGroup group, int index) {
-            mAdapter.update();
-        }
-
-        @Override
-        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
-            mAdapter.update();
-        }
-
-        @Override
-        public void onRouteVolumeChanged(MediaRouter router, RouteInfo info) {
-            if (!mIgnoreCallbackVolumeChanges) {
-                updateVolume();
-            }
-        }
-    }
-
-    class RouteComparator implements Comparator<RouteInfo> {
-        @Override
-        public int compare(RouteInfo lhs, RouteInfo rhs) {
-            return lhs.getName(getActivity()).toString()
-                    .compareTo(rhs.getName(getActivity()).toString());
-        }
-    }
-
-    class RouteChooserDialog extends Dialog {
-        public RouteChooserDialog(Context context, int theme) {
-            super(context, theme);
-        }
-
-        @Override
-        public void onBackPressed() {
-            if (mAdapter != null && mAdapter.isGrouping()) {
-                mAdapter.finishGrouping();
-            } else {
-                super.onBackPressed();
-            }
-        }
-        
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
-                final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
-                if (selectedRoute != null) {
-                    selectedRoute.requestUpdateVolume(-1);
-                    return true;
-                }
-            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
-                final RouteInfo selectedRoute = mRouter.getSelectedRoute(mRouteTypes);
-                if (selectedRoute != null) {
-                    mRouter.getSelectedRoute(mRouteTypes).requestUpdateVolume(1);
-                    return true;
-                }
-            }
-            return super.onKeyDown(keyCode, event);
-        }
-
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mVolumeSlider.isEnabled()) {
-                return true;
-            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mVolumeSlider.isEnabled()) {
-                return true;
-            } else {
-                return super.onKeyUp(keyCode, event);
+            MediaRouteChooserDialog dialog = (MediaRouteChooserDialog)getDialog();
+            if (dialog != null) {
+                dialog.setExtendedSettingsClickListener(listener);
             }
         }
     }
 
     /**
-     * Implemented by the MediaRouteButton that launched this dialog
+     * Called when the chooser dialog is being created.
+     * <p>
+     * Subclasses may override this method to customize the dialog.
+     * </p>
      */
-    public interface LauncherListener {
-        public void onDetached(MediaRouteChooserDialogFragment detachedFragment);
+    public MediaRouteChooserDialog onCreateChooserDialog(
+            Context context, Bundle savedInstanceState) {
+        return new MediaRouteChooserDialog(context, getTheme());
     }
 
-    class VolumeSliderChangeListener implements SeekBar.OnSeekBarChangeListener {
-
-        @Override
-        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-            changeVolume(progress);
-        }
-
-        @Override
-        public void onStartTrackingTouch(SeekBar seekBar) {
-            mIgnoreCallbackVolumeChanges = true;
-        }
-
-        @Override
-        public void onStopTrackingTouch(SeekBar seekBar) {
-            mIgnoreCallbackVolumeChanges = false;
-            updateVolume();
-        }
-
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        MediaRouteChooserDialog dialog = onCreateChooserDialog(getActivity(), savedInstanceState);
+        dialog.setRouteTypes(getRouteTypes());
+        dialog.setExtendedSettingsClickListener(mExtendedSettingsClickListener);
+        return dialog;
     }
 }
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialog.java b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
new file mode 100644
index 0000000..8fc99c7
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialog.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2013 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.android.internal.app;
+
+import com.android.internal.R;
+
+import android.app.Dialog;
+import android.app.MediaRouteActionProvider;
+import android.app.MediaRouteButton;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteGroup;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+
+/**
+ * This class implements the route controller dialog for {@link MediaRouter}.
+ * <p>
+ * This dialog allows the user to control or disconnect from the currently selected route.
+ * </p>
+ *
+ * @see MediaRouteButton
+ * @see MediaRouteActionProvider
+ *
+ * TODO: Move this back into the API, as in the support library media router.
+ */
+public class MediaRouteControllerDialog extends Dialog {
+    // Time to wait before updating the volume when the user lets go of the seek bar
+    // to allow the route provider time to propagate the change and publish a new
+    // route descriptor.
+    private static final int VOLUME_UPDATE_DELAY_MILLIS = 250;
+
+    private final MediaRouter mRouter;
+    private final MediaRouterCallback mCallback;
+    private final MediaRouter.RouteInfo mRoute;
+
+    private boolean mCreated;
+    private Drawable mMediaRouteConnectingDrawable;
+    private Drawable mMediaRouteOnDrawable;
+    private Drawable mCurrentIconDrawable;
+
+    private boolean mVolumeControlEnabled = true;
+    private LinearLayout mVolumeLayout;
+    private SeekBar mVolumeSlider;
+    private boolean mVolumeSliderTouched;
+
+    private View mControlView;
+
+    private Button mDisconnectButton;
+
+    public MediaRouteControllerDialog(Context context, int theme) {
+        super(context, theme);
+
+        mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        mCallback = new MediaRouterCallback();
+        mRoute = mRouter.getSelectedRoute();
+    }
+
+    /**
+     * Gets the route that this dialog is controlling.
+     */
+    public MediaRouter.RouteInfo getRoute() {
+        return mRoute;
+    }
+
+    /**
+     * Provides the subclass an opportunity to create a view that will
+     * be included within the body of the dialog to offer additional media controls
+     * for the currently playing content.
+     *
+     * @param savedInstanceState The dialog's saved instance state.
+     * @return The media control view, or null if none.
+     */
+    public View onCreateMediaControlView(Bundle savedInstanceState) {
+        return null;
+    }
+
+    /**
+     * Gets the media control view that was created by {@link #onCreateMediaControlView(Bundle)}.
+     *
+     * @return The media control view, or null if none.
+     */
+    public View getMediaControlView() {
+        return mControlView;
+    }
+
+    /**
+     * Sets whether to enable the volume slider and volume control using the volume keys
+     * when the route supports it.
+     * <p>
+     * The default value is true.
+     * </p>
+     */
+    public void setVolumeControlEnabled(boolean enable) {
+        if (mVolumeControlEnabled != enable) {
+            mVolumeControlEnabled = enable;
+            if (mCreated) {
+                updateVolume();
+            }
+        }
+    }
+
+    /**
+     * Returns whether to enable the volume slider and volume control using the volume keys
+     * when the route supports it.
+     */
+    public boolean isVolumeControlEnabled() {
+        return mVolumeControlEnabled;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
+
+        setContentView(R.layout.media_route_controller_dialog);
+
+        mVolumeLayout = (LinearLayout)findViewById(R.id.media_route_volume_layout);
+        mVolumeSlider = (SeekBar)findViewById(R.id.media_route_volume_slider);
+        mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            private final Runnable mStopTrackingTouch = new Runnable() {
+                @Override
+                public void run() {
+                    if (mVolumeSliderTouched) {
+                        mVolumeSliderTouched = false;
+                        updateVolume();
+                    }
+                }
+            };
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+                if (mVolumeSliderTouched) {
+                    mVolumeSlider.removeCallbacks(mStopTrackingTouch);
+                } else {
+                    mVolumeSliderTouched = true;
+                }
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+                // Defer resetting mVolumeSliderTouched to allow the media route provider
+                // a little time to settle into its new state and publish the final
+                // volume update.
+                mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS);
+            }
+
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                if (fromUser) {
+                    mRoute.requestSetVolume(progress);
+                }
+            }
+        });
+
+        mDisconnectButton = (Button)findViewById(R.id.media_route_disconnect_button);
+        mDisconnectButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mRoute.isSelected()) {
+                    mRouter.getDefaultRoute().select();
+                }
+                dismiss();
+            }
+        });
+
+        mCreated = true;
+        if (update()) {
+            mControlView = onCreateMediaControlView(savedInstanceState);
+            FrameLayout controlFrame =
+                    (FrameLayout)findViewById(R.id.media_route_control_frame);
+            if (mControlView != null) {
+                controlFrame.addView(mControlView);
+                controlFrame.setVisibility(View.VISIBLE);
+            } else {
+                controlFrame.setVisibility(View.GONE);
+            }
+        }
+    }
+
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        mRouter.addCallback(0, mCallback, MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS);
+        update();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        mRouter.removeCallback(mCallback);
+
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+            mRoute.requestUpdateVolume(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ? -1 : 1);
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    private boolean update() {
+        if (!mRoute.isSelected() || mRoute.isDefault()) {
+            dismiss();
+            return false;
+        }
+
+        setTitle(mRoute.getName());
+        updateVolume();
+
+        Drawable icon = getIconDrawable();
+        if (icon != mCurrentIconDrawable) {
+            mCurrentIconDrawable = icon;
+            getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, icon);
+        }
+        return true;
+    }
+
+    private Drawable getIconDrawable() {
+        if (mRoute.isConnecting()) {
+            if (mMediaRouteConnectingDrawable == null) {
+                mMediaRouteConnectingDrawable = getContext().getResources().getDrawable(
+                        R.drawable.ic_media_route_connecting_holo_dark);
+            }
+            return mMediaRouteConnectingDrawable;
+        } else {
+            if (mMediaRouteOnDrawable == null) {
+                mMediaRouteOnDrawable = getContext().getResources().getDrawable(
+                        R.drawable.ic_media_route_on_holo_dark);
+            }
+            return mMediaRouteOnDrawable;
+        }
+    }
+
+    private void updateVolume() {
+        if (!mVolumeSliderTouched) {
+            if (isVolumeControlAvailable()) {
+                mVolumeLayout.setVisibility(View.VISIBLE);
+                mVolumeSlider.setMax(mRoute.getVolumeMax());
+                mVolumeSlider.setProgress(mRoute.getVolume());
+            } else {
+                mVolumeLayout.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    private boolean isVolumeControlAvailable() {
+        return mVolumeControlEnabled && mRoute.getVolumeHandling() ==
+                MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+    }
+
+    private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+            update();
+        }
+
+        @Override
+        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
+            update();
+        }
+
+        @Override
+        public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) {
+            if (route == mRoute) {
+                updateVolume();
+            }
+        }
+
+        @Override
+        public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
+                int index) {
+            update();
+        }
+
+        @Override
+        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
+            update();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java b/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java
new file mode 100644
index 0000000..108e81f
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.android.internal.app;
+
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * Media route controller dialog fragment.
+ * <p>
+ * Creates a {@link MediaRouteControllerDialog}.  The application may subclass
+ * this dialog fragment to customize the media route controller dialog.
+ * </p>
+ *
+ * TODO: Move this back into the API, as in the support library media router.
+ */
+public class MediaRouteControllerDialogFragment extends DialogFragment {
+    /**
+     * Creates a media route controller dialog fragment.
+     * <p>
+     * All subclasses of this class must also possess a default constructor.
+     * </p>
+     */
+    public MediaRouteControllerDialogFragment() {
+        setCancelable(true);
+        setStyle(STYLE_NORMAL, android.R.style.Theme_DeviceDefault_Dialog);
+    }
+
+    /**
+     * Called when the controller dialog is being created.
+     * <p>
+     * Subclasses may override this method to customize the dialog.
+     * </p>
+     */
+    public MediaRouteControllerDialog onCreateControllerDialog(
+            Context context, Bundle savedInstanceState) {
+        return new MediaRouteControllerDialog(context, getTheme());
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return onCreateControllerDialog(getActivity(), savedInstanceState);
+    }
+}
diff --git a/core/java/com/android/internal/app/MediaRouteDialogPresenter.java b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
new file mode 100644
index 0000000..fad7fd4
--- /dev/null
+++ b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2013 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.android.internal.app;
+
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.media.MediaRouter;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * Shows media route dialog as appropriate.
+ * @hide
+ */
+public abstract class MediaRouteDialogPresenter {
+    private static final String TAG = "MediaRouter";
+
+    private static final String CHOOSER_FRAGMENT_TAG =
+            "android.app.MediaRouteButton:MediaRouteChooserDialogFragment";
+    private static final String CONTROLLER_FRAGMENT_TAG =
+            "android.app.MediaRouteButton:MediaRouteControllerDialogFragment";
+
+    public static DialogFragment showDialogFragment(Activity activity,
+            int routeTypes, View.OnClickListener extendedSettingsClickListener) {
+        final MediaRouter router = (MediaRouter)activity.getSystemService(
+                Context.MEDIA_ROUTER_SERVICE);
+        final FragmentManager fm = activity.getFragmentManager();
+
+        MediaRouter.RouteInfo route = router.getSelectedRoute();
+        if (route.isDefault() || !route.matchesTypes(routeTypes)) {
+            if (fm.findFragmentByTag(CHOOSER_FRAGMENT_TAG) != null) {
+                Log.w(TAG, "showDialog(): Route chooser dialog already showing!");
+                return null;
+            }
+            MediaRouteChooserDialogFragment f = new MediaRouteChooserDialogFragment();
+            f.setRouteTypes(routeTypes);
+            f.setExtendedSettingsClickListener(extendedSettingsClickListener);
+            f.show(fm, CHOOSER_FRAGMENT_TAG);
+            return f;
+        } else {
+            if (fm.findFragmentByTag(CONTROLLER_FRAGMENT_TAG) != null) {
+                Log.w(TAG, "showDialog(): Route controller dialog already showing!");
+                return null;
+            }
+            MediaRouteControllerDialogFragment f = new MediaRouteControllerDialogFragment();
+            f.show(fm, CONTROLLER_FRAGMENT_TAG);
+            return f;
+        }
+    }
+
+    public static Dialog createDialog(Context context,
+            int routeTypes, View.OnClickListener extendedSettingsClickListener) {
+        final MediaRouter router = (MediaRouter)context.getSystemService(
+                Context.MEDIA_ROUTER_SERVICE);
+
+        MediaRouter.RouteInfo route = router.getSelectedRoute();
+        if (route.isDefault() || !route.matchesTypes(routeTypes)) {
+            final MediaRouteChooserDialog d = new MediaRouteChooserDialog(
+                    context, android.R.style.Theme_DeviceDefault_Dialog);
+            d.setRouteTypes(routeTypes);
+            d.setExtendedSettingsClickListener(extendedSettingsClickListener);
+            return d;
+        } else {
+            MediaRouteControllerDialog d = new MediaRouteControllerDialog(
+                    context, android.R.style.Theme_DeviceDefault_Dialog);
+            return d;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 20b8c95..0cad33c 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1758,21 +1758,34 @@
                 mStartTime, now);
         ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
         boolean printedHeader = false;
+        boolean sepNeeded = false;
         for (int ip=0; ip<pkgMap.size(); ip++) {
-            String pkgName = pkgMap.keyAt(ip);
-            if (reqPackage != null && !reqPackage.equals(pkgName)) {
-                continue;
-            }
-            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            final String pkgName = pkgMap.keyAt(ip);
+            final SparseArray<PackageState> uids = pkgMap.valueAt(ip);
             for (int iu=0; iu<uids.size(); iu++) {
-                int uid = uids.keyAt(iu);
-                PackageState pkgState = uids.valueAt(iu);
+                final int uid = uids.keyAt(iu);
+                final PackageState pkgState = uids.valueAt(iu);
                 final int NPROCS = pkgState.mProcesses.size();
                 final int NSRVS = pkgState.mServices.size();
+                final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+                if (!pkgMatch) {
+                    boolean procMatch = false;
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (reqPackage.equals(proc.mName)) {
+                            procMatch = true;
+                            break;
+                        }
+                    }
+                    if (!procMatch) {
+                        continue;
+                    }
+                }
                 if (NPROCS > 0 || NSRVS > 0) {
                     if (!printedHeader) {
                         pw.println("Per-Package Stats:");
                         printedHeader = true;
+                        sepNeeded = true;
                     }
                     pw.print("  * "); pw.print(pkgName); pw.print(" / ");
                             UserHandle.formatUid(pw, uid); pw.println(":");
@@ -1780,6 +1793,9 @@
                 if (!dumpSummary || dumpAll) {
                     for (int iproc=0; iproc<NPROCS; iproc++) {
                         ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+                            continue;
+                        }
                         if (activeOnly && !proc.isInUse()) {
                             pw.print("      (Not active: ");
                                     pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
@@ -1787,7 +1803,11 @@
                         }
                         pw.print("      Process ");
                         pw.print(pkgState.mProcesses.keyAt(iproc));
-                        pw.print(" (");
+                        if (proc.mCommonProcess.mMultiPackage) {
+                            pw.print(" (multi, ");
+                        } else {
+                            pw.print(" (unique, ");
+                        }
                         pw.print(proc.mDurationsTableSize);
                         pw.print(" entries)");
                         pw.println(":");
@@ -1801,6 +1821,9 @@
                     ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
                     for (int iproc=0; iproc<NPROCS; iproc++) {
                         ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+                            continue;
+                        }
                         if (activeOnly && !proc.isInUse()) {
                             continue;
                         }
@@ -1811,6 +1834,9 @@
                 }
                 for (int isvc=0; isvc<NSRVS; isvc++) {
                     ServiceState svc = pkgState.mServices.valueAt(isvc);
+                    if (!pkgMatch && !reqPackage.equals(svc.mProcessName)) {
+                        continue;
+                    }
                     if (activeOnly && !svc.isInUse()) {
                         pw.print("      (Not active: ");
                                 pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
@@ -1840,64 +1866,73 @@
                         if (svc.mOwner != null) {
                             pw.print("        mOwner="); pw.println(svc.mOwner);
                         }
+                        if (svc.mStarted || svc.mRestarting) {
+                            pw.print("        mStarted="); pw.print(svc.mStarted);
+                            pw.print(" mRestarting="); pw.println(svc.mRestarting);
+                        }
                     }
                 }
             }
         }
 
-        if (reqPackage == null) {
-            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-            printedHeader = false;
-            int numShownProcs = 0, numTotalProcs = 0;
-            for (int ip=0; ip<procMap.size(); ip++) {
-                String procName = procMap.keyAt(ip);
-                SparseArray<ProcessState> uids = procMap.valueAt(ip);
-                for (int iu=0; iu<uids.size(); iu++) {
-                    int uid = uids.keyAt(iu);
-                    numTotalProcs++;
-                    ProcessState proc = uids.valueAt(iu);
-                    if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
-                            && proc.mPssTableSize == 0) {
-                        continue;
-                    }
-                    numShownProcs++;
-                    if (!printedHeader) {
-                        pw.println();
-                        pw.println("Per-Process Stats:");
-                        printedHeader = true;
-                    }
-                    if (activeOnly && !proc.isInUse()) {
-                        pw.print("      (Not active: "); pw.print(procName); pw.println(")");
-                        continue;
-                    }
-                    pw.print("  * "); pw.print(procName); pw.print(" / ");
-                            UserHandle.formatUid(pw, uid);
-                            pw.print(" ("); pw.print(proc.mDurationsTableSize);
-                            pw.print(" entries)"); pw.println(":");
-                    dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                            ALL_PROC_STATES, now);
-                    dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                            ALL_PROC_STATES);
-                    if (dumpAll) {
-                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
-                    }
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        printedHeader = false;
+        int numShownProcs = 0, numTotalProcs = 0;
+        for (int ip=0; ip<procMap.size(); ip++) {
+            String procName = procMap.keyAt(ip);
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                numTotalProcs++;
+                ProcessState proc = uids.valueAt(iu);
+                if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
+                        && proc.mPssTableSize == 0) {
+                    continue;
                 }
+                if (!proc.mMultiPackage) {
+                    continue;
+                }
+                if (reqPackage != null && !reqPackage.equals(procName)
+                        && !reqPackage.equals(proc.mPackage)) {
+                    continue;
+                }
+                numShownProcs++;
+                if (sepNeeded) {
+                    pw.println();
+                }
+                sepNeeded = true;
+                if (!printedHeader) {
+                    pw.println("Multi-Package Common Processes:");
+                    printedHeader = true;
+                }
+                if (activeOnly && !proc.isInUse()) {
+                    pw.print("      (Not active: "); pw.print(procName); pw.println(")");
+                    continue;
+                }
+                pw.print("  * "); pw.print(procName); pw.print(" / ");
+                        UserHandle.formatUid(pw, uid);
+                        pw.print(" ("); pw.print(proc.mDurationsTableSize);
+                        pw.print(" entries)"); pw.println(":");
+                dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                        ALL_PROC_STATES, now);
+                dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                        ALL_PROC_STATES);
+                dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
             }
-            if (dumpAll) {
-                pw.println();
-                pw.print("  Total procs: "); pw.print(numShownProcs);
-                        pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
-            }
+        }
+        if (dumpAll) {
+            pw.println();
+            pw.print("  Total procs: "); pw.print(numShownProcs);
+                    pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+        }
 
+        if (sepNeeded) {
             pw.println();
-            if (dumpSummary) {
-                pw.println("Summary:");
-                dumpSummaryLocked(pw, reqPackage, now, activeOnly);
-            } else {
-                dumpTotalsLocked(pw, now);
-            }
+        }
+        if (dumpSummary) {
+            pw.println("Summary:");
+            dumpSummaryLocked(pw, reqPackage, now, activeOnly);
         } else {
-            pw.println();
             dumpTotalsLocked(pw, now);
         }
 
@@ -2031,17 +2066,20 @@
     public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
             int[] procStates, int sortProcStates[], long now, String reqPackage,
             boolean activeOnly) {
-        ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
-        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+        final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
+        final ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
         for (int ip=0; ip<pkgMap.size(); ip++) {
-            if (reqPackage != null && !reqPackage.equals(pkgMap.keyAt(ip))) {
-                continue;
-            }
-            SparseArray<PackageState> procs = pkgMap.valueAt(ip);
+            final String pkgName = pkgMap.keyAt(ip);
+            final SparseArray<PackageState> procs = pkgMap.valueAt(ip);
             for (int iu=0; iu<procs.size(); iu++) {
-                PackageState state = procs.valueAt(iu);
-                for (int iproc=0; iproc<state.mProcesses.size(); iproc++) {
-                    ProcessState proc = state.mProcesses.valueAt(iproc);
+                final PackageState state = procs.valueAt(iu);
+                final int NPROCS = state.mProcesses.size();
+                final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+                for (int iproc=0; iproc<NPROCS; iproc++) {
+                    final ProcessState proc = state.mProcesses.valueAt(iproc);
+                    if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+                        continue;
+                    }
                     if (activeOnly && !proc.isInUse()) {
                         continue;
                     }
@@ -2601,23 +2639,35 @@
             }
         }
 
-        void incStartedServices(int memFactor, long now) {
+        void incStartedServices(int memFactor, long now, String serviceName) {
+            if (false) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
+                        + " to " + (mNumStartedServices+1), here);
+            }
             if (mCommonProcess != this) {
-                mCommonProcess.incStartedServices(memFactor, now);
+                mCommonProcess.incStartedServices(memFactor, now, serviceName);
             }
             mNumStartedServices++;
             if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
-                setState(STATE_NOTHING, memFactor, now, null);
+                setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
             }
         }
 
-        void decStartedServices(int memFactor, long now) {
+        void decStartedServices(int memFactor, long now, String serviceName) {
+            if (false) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+                        + " to " + (mNumStartedServices-1), here);
+            }
             if (mCommonProcess != this) {
-                mCommonProcess.decStartedServices(memFactor, now);
+                mCommonProcess.decStartedServices(memFactor, now, serviceName);
             }
             mNumStartedServices--;
-            if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) {
-                setState(STATE_NOTHING, memFactor, now, null);
+            if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
+                setState(STATE_NOTHING, now);
             } else if (mNumStartedServices < 0) {
                 Slog.wtfStack(TAG, "Proc started services underrun: pkg="
                         + mPackage + " uid=" + mUid + " name=" + mName);
@@ -2873,6 +2923,8 @@
         public int mRunState = STATE_NOTHING;
         long mRunStartTime;
 
+        boolean mStarted;
+        boolean mRestarting;
         int mStartedCount;
         public int mStartedState = STATE_NOTHING;
         long mStartedStartTime;
@@ -2902,10 +2954,9 @@
                     // There was already an old owner, reset this object for its
                     // new owner.
                     mOwner = newOwner;
-                    if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
-                            || mExecState != STATE_NOTHING) {
+                    if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
                         long now = SystemClock.uptimeMillis();
-                        if (mStartedState != STATE_NOTHING) {
+                        if (mStarted) {
                             if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
                                     + " from " + mOwner + " while started: pkg="
                                     + mPackage + " service=" + mName + " proc=" + mProc);
@@ -2931,10 +2982,9 @@
         public void clearCurrentOwner(Object owner, boolean silently) {
             if (mOwner == owner) {
                 mProc.decActiveServices(mName);
-                if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
-                        || mExecState != STATE_NOTHING) {
+                if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
                     long now = SystemClock.uptimeMillis();
-                    if (mStartedState != STATE_NOTHING) {
+                    if (mStarted) {
                         if (!silently) {
                             Slog.wtfStack(TAG, "Service owner " + owner
                                     + " cleared while started: pkg=" + mPackage + " service="
@@ -3042,7 +3092,18 @@
             if (mOwner == null) {
                 Slog.wtf(TAG, "Starting service " + this + " without owner");
             }
+            mStarted = started;
+            updateStartedState(memFactor, now);
+        }
+
+        public void setRestarting(boolean restarting, int memFactor, long now) {
+            mRestarting = restarting;
+            updateStartedState(memFactor, now);
+        }
+
+        void updateStartedState(int memFactor, long now) {
             final boolean wasStarted = mStartedState != STATE_NOTHING;
+            final boolean started = mStarted || mRestarting;
             final int state = started ? memFactor : STATE_NOTHING;
             if (mStartedState != state) {
                 if (mStartedState != STATE_NOTHING) {
@@ -3056,9 +3117,9 @@
                 mProc = mProc.pullFixedProc(mPackage);
                 if (wasStarted != started) {
                     if (started) {
-                        mProc.incStartedServices(memFactor, now);
+                        mProc.incStartedServices(memFactor, now, mName);
                     } else {
-                        mProc.decStartedServices(memFactor, now);
+                        mProc.decStartedServices(memFactor, now, mName);
                     }
                 }
                 updateRunning(memFactor, now);
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 5bfa1b2..1e37fd9 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -23,6 +23,12 @@
 
 /** {@hide} */
 interface IBackupTransport {
+    /**
+     * Ask the transport for the name under which it should be registered.  This will
+     * typically be its host service's component name, but need not be.
+     */
+    String name();
+
 	/**
 	 * Ask the transport for an Intent that can be used to launch any internal
 	 * configuration Activity that it wishes to present.  For example, the transport
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index eb2d1fe..494bc78 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -19,6 +19,7 @@
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.RestoreSet;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -71,6 +72,10 @@
         }
     }
 
+    public String name() {
+        return new ComponentName(mContext, this.getClass()).flattenToShortString();
+    }
+
     public Intent configurationIntent() {
         // The local transport is not user-configurable
         return null;
diff --git a/core/java/com/android/internal/backup/LocalTransportService.java b/core/java/com/android/internal/backup/LocalTransportService.java
new file mode 100644
index 0000000..d05699a
--- /dev/null
+++ b/core/java/com/android/internal/backup/LocalTransportService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 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.android.internal.backup;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class LocalTransportService extends Service {
+    private static LocalTransport sTransport = null;
+
+    @Override
+    public void onCreate() {
+        if (sTransport == null) {
+            sTransport = new LocalTransport(this);
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return sTransport;
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a99aa33..0a702ff 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -84,7 +84,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 66 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 67 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -154,6 +154,8 @@
     final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>();
     final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>();
     final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<StopwatchTimer>();
+    final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers =
+            new SparseArray<ArrayList<StopwatchTimer>>();
 
     // Last partial timers we use for distributing CPU usage.
     final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>();
@@ -2404,6 +2406,14 @@
         getUidStatsLocked(uid).noteWifiScanStoppedLocked();
     }
 
+    public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
+        getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph);
+    }
+
+    public void noteWifiBatchedScanStoppedLocked(int uid) {
+        getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked();
+    }
+
     int mWifiMulticastNesting = 0;
 
     public void noteWifiMulticastEnabledLocked(int uid) {
@@ -2456,6 +2466,20 @@
         }
     }
 
+    public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteWifiBatchedScanStartedLocked(ws.get(i), csph);
+        }
+    }
+
+    public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteWifiBatchedScanStoppedLocked(ws.get(i));
+        }
+    }
+
     public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
@@ -2579,6 +2603,10 @@
         boolean mWifiScanStarted;
         StopwatchTimer mWifiScanTimer;
 
+        private static final int NO_BATCHED_SCAN_STARTED = -1;
+        int mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+        StopwatchTimer[] mWifiBatchedScanTimer;
+
         boolean mWifiMulticastEnabled;
         StopwatchTimer mWifiMulticastTimer;
 
@@ -2629,6 +2657,7 @@
                     mFullWifiLockTimers, mUnpluggables);
             mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
                     mWifiScanTimers, mUnpluggables);
+            mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
             mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
                     mWifiMulticastTimers, mUnpluggables);
         }
@@ -2719,6 +2748,36 @@
         }
 
         @Override
+        public void noteWifiBatchedScanStartedLocked(int csph) {
+            int bin = 0;
+            while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
+                csph = csph >> 3;
+                bin++;
+            }
+
+            if (mWifiBatchedScanBinStarted == bin) return;
+
+            if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
+                mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
+                        stopRunningLocked(BatteryStatsImpl.this);
+            }
+            mWifiBatchedScanBinStarted = bin;
+            if (mWifiBatchedScanTimer[bin] == null) {
+                makeWifiBatchedScanBin(bin, null);
+            }
+            mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this);
+        }
+
+        @Override
+        public void noteWifiBatchedScanStoppedLocked() {
+            if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
+                mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
+                        stopRunningLocked(BatteryStatsImpl.this);
+                mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+            }
+        }
+
+        @Override
         public void noteWifiMulticastEnabledLocked() {
             if (!mWifiMulticastEnabled) {
                 mWifiMulticastEnabled = true;
@@ -2854,6 +2913,15 @@
         }
 
         @Override
+        public long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which) {
+            if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
+            if (mWifiBatchedScanTimer[csphBin] == null) {
+                return 0;
+            }
+            return mWifiBatchedScanTimer[csphBin].getTotalTimeLocked(batteryRealtime, which);
+        }
+
+        @Override
         public long getWifiMulticastTime(long batteryRealtime, int which) {
             if (mWifiMulticastTimer == null) {
                 return 0;
@@ -2914,6 +2982,24 @@
             return mUserActivityCounters[type].getCountLocked(which);
         }
 
+        void makeWifiBatchedScanBin(int i, Parcel in) {
+            if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
+
+            ArrayList<StopwatchTimer> collected = mWifiBatchedScanTimers.get(i);
+            if (collected == null) {
+                collected = new ArrayList<StopwatchTimer>();
+                mWifiBatchedScanTimers.put(i, collected);
+            }
+            if (in == null) {
+                mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
+                        mUnpluggables);
+            } else {
+                mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
+                        mUnpluggables, in);
+            }
+        }
+
+
         void initUserActivityLocked() {
             mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
             for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
@@ -2974,6 +3060,14 @@
                 active |= !mWifiScanTimer.reset(BatteryStatsImpl.this, false);
                 active |= mWifiScanStarted;
             }
+            if (mWifiBatchedScanTimer != null) {
+                for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                    if (mWifiBatchedScanTimer[i] != null) {
+                        active |= !mWifiBatchedScanTimer[i].reset(BatteryStatsImpl.this, false);
+                    }
+                }
+                active |= (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED);
+            }
             if (mWifiMulticastTimer != null) {
                 active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
                 active |= mWifiMulticastEnabled;
@@ -3080,6 +3174,11 @@
                 if (mWifiScanTimer != null) {
                     mWifiScanTimer.detach();
                 }
+                for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                    if (mWifiBatchedScanTimer[i] != null) {
+                        mWifiBatchedScanTimer[i].detach();
+                    }
+                }
                 if (mWifiMulticastTimer != null) {
                     mWifiMulticastTimer.detach();
                 }
@@ -3157,6 +3256,14 @@
             } else {
                 out.writeInt(0);
             }
+            for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (mWifiBatchedScanTimer[i] != null) {
+                    out.writeInt(1);
+                    mWifiBatchedScanTimer[i].writeToParcel(out, batteryRealtime);
+                } else {
+                    out.writeInt(0);
+                }
+            }
             if (mWifiMulticastTimer != null) {
                 out.writeInt(1);
                 mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
@@ -3266,6 +3373,14 @@
             } else {
                 mWifiScanTimer = null;
             }
+            mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+            for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (in.readInt() != 0) {
+                    makeWifiBatchedScanBin(i, in);
+                } else {
+                    mWifiBatchedScanTimer[i] = null;
+                }
+            }
             mWifiMulticastEnabled = false;
             if (in.readInt() != 0) {
                 mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
@@ -5463,6 +5578,13 @@
             if (in.readInt() != 0) {
                 u.mWifiScanTimer.readSummaryFromParcelLocked(in);
             }
+            u.mWifiBatchedScanBinStarted = Uid.NO_BATCHED_SCAN_STARTED;
+            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (in.readInt() != 0) {
+                    u.makeWifiBatchedScanBin(i, null);
+                    u.mWifiBatchedScanTimer[i].readSummaryFromParcelLocked(in);
+                }
+            }
             u.mWifiMulticastEnabled = false;
             if (in.readInt() != 0) {
                 u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
@@ -5674,6 +5796,14 @@
             } else {
                 out.writeInt(0);
             }
+            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (u.mWifiBatchedScanTimer[i] != null) {
+                    out.writeInt(1);
+                    u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+                } else {
+                    out.writeInt(0);
+                }
+            }
             if (u.mWifiMulticastTimer != null) {
                 out.writeInt(1);
                 u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
@@ -5909,6 +6039,7 @@
         mWifiRunningTimers.clear();
         mFullWifiLockTimers.clear();
         mWifiScanTimers.clear();
+        mWifiBatchedScanTimers.clear();
         mWifiMulticastTimers.clear();
 
         sNumSpeedSteps = in.readInt();
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 99a6843..94750d3 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -136,6 +136,13 @@
     public static final String POWER_CPU_SPEEDS = "cpu.speeds";
 
     /**
+     * Power consumed by wif batched scaning.  Broken down into bins by
+     * Channels Scanned per Hour.  May do 1-720 scans per hour of 1-100 channels
+     * for a range of 1-72,000.  Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)!
+     */
+    public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan";
+
+    /**
      * Battery capacity in milliAmpHour (mAh).
      */
     public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
@@ -171,7 +178,7 @@
 
                 String element = parser.getName();
                 if (element == null) break;
-                
+
                 if (parsingArray && !element.equals(TAG_ARRAYITEM)) {
                     // Finish array
                     sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
diff --git a/core/java/com/android/internal/view/CheckableLinearLayout.java b/core/java/com/android/internal/view/CheckableLinearLayout.java
deleted file mode 100644
index 3fb7cec..0000000
--- a/core/java/com/android/internal/view/CheckableLinearLayout.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.android.internal.view;
-
-import com.android.internal.R;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.Checkable;
-import android.widget.CheckBox;
-import android.widget.LinearLayout;
-
-public class CheckableLinearLayout extends LinearLayout implements Checkable {
-    private CheckBox mCheckBox;
-
-    public CheckableLinearLayout(Context context) {
-        super(context);
-        // TODO Auto-generated constructor stub
-    }
-
-    public CheckableLinearLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        // TODO Auto-generated constructor stub
-    }
-
-    public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        // TODO Auto-generated constructor stub
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mCheckBox = (CheckBox) findViewById(R.id.check);
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-        mCheckBox.setChecked(checked);
-    }
-
-    @Override
-    public boolean isChecked() {
-        return mCheckBox.isChecked();
-    }
-
-    @Override
-    public void toggle() {
-        mCheckBox.toggle();
-    }
-}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 5f9d8f2..786f5cf 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -526,7 +526,7 @@
         if (mLogoNavItem != null) {
             mLogoNavItem.setTitle(title);
         }
-        mUpGoerFive.setContentDescription(buildHomeContentDescription());
+        updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
     public CharSequence getSubtitle() {
@@ -544,7 +544,7 @@
                     (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle));
             mTitleLayout.setVisibility(visible ? VISIBLE : GONE);
         }
-        mUpGoerFive.setContentDescription(buildHomeContentDescription());
+        updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
     public void setHomeButtonEnabled(boolean enable) {
@@ -681,7 +681,7 @@
         }
 
         // Make sure the home button has an accurate content description for accessibility.
-        updateHomeAccessibility(!mUpGoerFive.isEnabled());
+        updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
     public void setIcon(Drawable icon) {
@@ -1332,11 +1332,13 @@
 
     public void setHomeActionContentDescription(CharSequence description) {
         mHomeDescription = description;
+        updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
     public void setHomeActionContentDescription(int resId) {
         mHomeDescriptionRes = resId;
         mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
+        updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
     static class SavedState extends BaseSavedState {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6ddd3fe..b198937 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1992,6 +1992,14 @@
         android:description="@string/permdesc_bindWallpaper"
         android:protectionLevel="signature|system" />
 
+    <!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
+         to ensure that only the system can bind to it.
+         @hide -->
+    <permission android:name="android.permission.BIND_REMOTE_DISPLAY"
+        android:label="@string/permlab_bindRemoteDisplay"
+        android:description="@string/permdesc_bindRemoteDisplay"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by device administration receiver, to ensure that only the
          system can interact with it. -->
     <permission android:name="android.permission.BIND_DEVICE_ADMIN"
@@ -2681,6 +2689,15 @@
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
+
+        <service android:name="com.android.internal.backup.LocalTransportService"
+                android:permission="android.permission.CONFIRM_FULL_BACKUP"
+                android:exported="false">
+            <intent-filter>
+                <action android:name="android.backup.TRANSPORT_HOST" />
+            </intent-filter>
+        </service>
+
     </application>
 
 </manifest>
diff --git a/core/res/res/drawable-hdpi/ic_media_group_collapse.png b/core/res/res/drawable-hdpi/ic_media_group_collapse.png
deleted file mode 100644
index 89abf2c..0000000
--- a/core/res/res/drawable-hdpi/ic_media_group_collapse.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_group_expand.png b/core/res/res/drawable-hdpi/ic_media_group_expand.png
deleted file mode 100644
index d9470b2..0000000
--- a/core/res/res/drawable-hdpi/ic_media_group_expand.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
index b47d666..458a2a6 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
index 13d803c..c91faa9 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
index 3ae436b..14c9183 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png
index 24824fc..b388d86 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png
index af3819b..76c1323 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png
index 83dc251..fd39f9d 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png
index 8d9d592..c74727a 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png
index 1310ec9..826c9ae 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png
index 1705074..d0baec3 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
index 7027b88..c60ff59 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
index 7027b88..75552cc 100644
--- a/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_0.png b/core/res/res/drawable-hdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..a35f281
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_1.png b/core/res/res/drawable-hdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..9f6e2ad
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_2.png b/core/res/res/drawable-hdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..737137a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_on.png b/core/res/res/drawable-hdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..ff2753a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index 35f27df..0000000
--- a/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_group_collapse.png b/core/res/res/drawable-mdpi/ic_media_group_collapse.png
deleted file mode 100644
index 34454ac..0000000
--- a/core/res/res/drawable-mdpi/ic_media_group_collapse.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_group_expand.png b/core/res/res/drawable-mdpi/ic_media_group_expand.png
deleted file mode 100644
index 8ce5a44..0000000
--- a/core/res/res/drawable-mdpi/ic_media_group_expand.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
index 6764598..9d92648 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
index 94e0bb6..3e27fc8 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png
index 5ce2f20..72b9e78 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png
index 5105e90..bd462a2 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png
index 68c06ed..0a2cc89 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png
index 6e9b144..d162503 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png
index 45dc56f3d..997e32b 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png
index 46e743a..d314967 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
index e384691..f15d7a9 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
index e384691..26d46f8 100644
--- a/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_0.png b/core/res/res/drawable-mdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..d9cedbd
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_1.png b/core/res/res/drawable-mdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..414c67f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_2.png b/core/res/res/drawable-mdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..280a888
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_on.png b/core/res/res/drawable-mdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..ab5f1d7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index f9c8678..0000000
--- a/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_group_collapse.png b/core/res/res/drawable-xhdpi/ic_media_group_collapse.png
deleted file mode 100644
index 2fb7428..0000000
--- a/core/res/res/drawable-xhdpi/ic_media_group_collapse.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_group_expand.png b/core/res/res/drawable-xhdpi/ic_media_group_expand.png
deleted file mode 100644
index 5755b9d..0000000
--- a/core/res/res/drawable-xhdpi/ic_media_group_expand.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
index 1d48e12..045eee0 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
index 2c8d1ec..6e14e29 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
index 00b2043..121bbf6 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
index ce1d939..468a0c3 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png
index 3064b46..414a322 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png
index 4316686..6088a48 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png
index 25c4e31..363d7d4 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png
index 8e32bd2..edf731e 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png
index aeaa78f..85cba7b 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png
index 85277fa..e65ac31 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
index b01dbe8..d8e3e3a 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
index c19a2ad..562dc9a 100644
--- a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_0.png b/core/res/res/drawable-xhdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..5fb23a0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_1.png b/core/res/res/drawable-xhdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..f01d17d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_2.png b/core/res/res/drawable-xhdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..4f4ba7f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_on.png b/core/res/res/drawable-xhdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..38f15dd
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index 4cc0ee8..0000000
--- a/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
index 7b0c383..178774c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
index efb624e..2dc2092 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
index 5ee57e4..592ee8c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
index 6bc2e4a..f0549e2 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
index c13af9c..91268f5 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
index 744fb42..9d5436f 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
index ca4d59c..8e77483 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
index fde5688..f396d22 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
index b8715c3..260bab4 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
index 668bb25..2c9fb1d 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
index 7f54a62..bdbd59c 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
index 2df924d..f5c33dd 100644
--- a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
+++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png
new file mode 100644
index 0000000..f5b16ed
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png
new file mode 100644
index 0000000..22efeec
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png
new file mode 100644
index 0000000..e24cd97
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png
new file mode 100644
index 0000000..da1a627
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png
deleted file mode 100644
index fea4774..0000000
--- a/core/res/res/drawable-xxhdpi/ic_notify_wifidisplay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/ic_notification_cast_connecting.xml b/core/res/res/drawable/ic_notification_cast_connecting.xml
new file mode 100644
index 0000000..a390bce
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_cast_connecting.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2013, 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.
+ */
+-->
+<animation-list
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="false">
+    <item android:drawable="@drawable/ic_notification_cast_0" android:duration="500" />
+    <item android:drawable="@drawable/ic_notification_cast_1" android:duration="500" />
+    <item android:drawable="@drawable/ic_notification_cast_2" android:duration="500" />
+    <item android:drawable="@drawable/ic_notification_cast_1" android:duration="500" />
+</animation-list>
diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml
index f97225e..c0cd93d 100644
--- a/core/res/res/layout/immersive_mode_cling.xml
+++ b/core/res/res/layout/immersive_mode_cling.xml
@@ -37,8 +37,8 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:background="@drawable/cling_bg"
-            android:paddingLeft="14dp"
-            android:paddingRight="14dp"
+            android:paddingStart="14dp"
+            android:paddingEnd="14dp"
             android:paddingTop="24dp"
             android:paddingBottom="24dp">
             <TextView
diff --git a/core/res/res/layout/media_route_chooser_dialog.xml b/core/res/res/layout/media_route_chooser_dialog.xml
new file mode 100644
index 0000000..d1c6267
--- /dev/null
+++ b/core/res/res/layout/media_route_chooser_dialog.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical"
+              android:divider="?android:attr/dividerHorizontal"
+              android:showDividers="middle">
+    <!-- List of routes. -->
+    <ListView android:id="@+id/media_route_list"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:layout_weight="1" />
+
+    <!-- Content to show when list is empty. -->
+    <LinearLayout android:id="@android:id/empty"
+              android:layout_width="match_parent"
+              android:layout_height="64dp"
+              android:orientation="horizontal"
+              android:paddingLeft="16dp"
+              android:paddingRight="16dp"
+              android:visibility="gone">
+        <ProgressBar android:layout_width="wrap_content"
+                     android:layout_height="wrap_content"
+                     android:layout_gravity="center" />
+        <TextView android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="center"
+                  android:paddingLeft="16dp"
+                  android:text="@string/media_route_chooser_searching" />
+    </LinearLayout>
+
+    <!-- Settings button. -->
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  style="?attr/buttonBarStyle">
+        <Button android:id="@+id/media_route_extended_settings_button"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                style="?attr/buttonBarButtonStyle"
+                android:gravity="center"
+                android:text="@string/media_route_chooser_extended_settings"
+                android:visibility="gone" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/media_route_chooser_layout.xml b/core/res/res/layout/media_route_chooser_layout.xml
deleted file mode 100644
index 5fcb8c8..0000000
--- a/core/res/res/layout/media_route_chooser_layout.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content"
-              android:orientation="vertical"
-              android:showDividers="middle"
-              android:divider="?android:attr/dividerHorizontal">
-    <LinearLayout android:layout_width="match_parent"
-                  android:layout_height="?android:attr/listPreferredItemHeight"
-                  android:gravity="center_vertical"
-                  android:padding="8dp">
-        <ImageView android:id="@+id/volume_icon"
-                   android:layout_width="48dp"
-                   android:layout_height="48dp"
-                   android:src="@android:drawable/ic_audio_vol"
-                   android:gravity="center"
-                   android:scaleType="center" />
-        <SeekBar android:id="@+id/volume_slider"
-                 android:layout_width="0dp"
-                 android:layout_height="wrap_content"
-                 android:layout_weight="1"
-                 android:layout_marginStart="8dp"
-                 android:layout_marginEnd="8dp" />
-        <ImageButton android:id="@+id/extended_settings"
-                     android:layout_width="48dp"
-                     android:layout_height="48dp"
-                     android:background="?android:attr/selectableItemBackground"
-                     android:src="@android:drawable/ic_sysbar_quicksettings"
-                     android:visibility="gone" />
-    </LinearLayout>
-    <ListView android:id="@id/list"
-              android:layout_width="match_parent"
-              android:layout_height="wrap_content" />
-</LinearLayout>
diff --git a/core/res/res/layout/media_route_controller_dialog.xml b/core/res/res/layout/media_route_controller_dialog.xml
new file mode 100644
index 0000000..78287e0
--- /dev/null
+++ b/core/res/res/layout/media_route_controller_dialog.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical"
+              android:divider="?android:attr/dividerHorizontal"
+              android:showDividers="middle">
+    <!-- Optional volume slider section. -->
+    <LinearLayout android:id="@+id/media_route_volume_layout"
+                  android:layout_width="match_parent"
+                  android:layout_height="64dp"
+                  android:gravity="center_vertical"
+                  android:padding="8dp"
+                  android:visibility="gone">
+        <ImageView android:layout_width="48dp"
+                   android:layout_height="48dp"
+                   android:src="@drawable/ic_audio_vol"
+                   android:gravity="center"
+                   android:scaleType="center" />
+        <SeekBar android:id="@+id/media_route_volume_slider"
+                 android:layout_width="0dp"
+                 android:layout_height="wrap_content"
+                 android:layout_weight="1"
+                 android:layout_marginLeft="8dp"
+                 android:layout_marginRight="8dp" />
+    </LinearLayout>
+
+    <!-- Optional content view section. -->
+    <FrameLayout android:id="@+id/media_route_control_frame"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:visibility="gone" />
+
+    <!-- Disconnect button. -->
+    <LinearLayout android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  style="?attr/buttonBarStyle">
+        <Button android:id="@+id/media_route_disconnect_button"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                style="?attr/buttonBarButtonStyle"
+                android:gravity="center"
+                android:text="@string/media_route_controller_disconnect" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/media_route_list_item.xml b/core/res/res/layout/media_route_list_item.xml
index 423d544..bdca433 100644
--- a/core/res/res/layout/media_route_list_item.xml
+++ b/core/res/res/layout/media_route_list_item.xml
@@ -20,13 +20,6 @@
               android:background="@drawable/item_background_activated_holo_dark"
               android:gravity="center_vertical">
 
-    <ImageView android:layout_width="56dp"
-               android:layout_height="56dp"
-               android:scaleType="center"
-               android:id="@+id/icon"
-               android:visibility="gone"
-               android:duplicateParentState="true" />
-
     <LinearLayout android:layout_width="0dp"
                   android:layout_height="match_parent"
                   android:layout_weight="1"
@@ -53,14 +46,4 @@
                   android:duplicateParentState="true" />
     </LinearLayout>
 
-    <ImageButton
-        android:layout_width="56dp"
-        android:layout_height="56dp"
-        android:id="@+id/expand_button"
-        android:background="?android:attr/selectableItemBackground"
-        android:src="@drawable/ic_media_group_expand"
-        android:scaleType="center"
-        android:visibility="gone"
-        android:duplicateParentState="true" />
-
 </LinearLayout>
diff --git a/core/res/res/layout/media_route_list_item_checkable.xml b/core/res/res/layout/media_route_list_item_checkable.xml
deleted file mode 100644
index 5fb82f7..0000000
--- a/core/res/res/layout/media_route_list_item_checkable.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?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.
--->
-
-<com.android.internal.view.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="?android:attr/listPreferredItemHeight"
-              android:background="?android:attr/selectableItemBackground"
-              android:gravity="center_vertical">
-
-    <ImageView android:layout_width="56dp"
-               android:layout_height="56dp"
-               android:scaleType="center"
-               android:id="@+id/icon"
-               android:visibility="gone" />
-
-    <LinearLayout android:layout_width="0dp"
-                  android:layout_height="match_parent"
-                  android:layout_weight="1"
-                  android:orientation="vertical"
-                  android:gravity="start|center_vertical"
-                  android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-                  android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
-        <TextView android:id="@android:id/text1"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:ellipsize="marquee"
-                  android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        <TextView android:id="@android:id/text2"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:ellipsize="marquee"
-                  android:textAppearance="?android:attr/textAppearanceSmall" />
-    </LinearLayout>
-
-    <CheckBox
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="16dp"
-        android:id="@+id/check"
-        android:focusable="false"
-        android:clickable="false" />
-
-</com.android.internal.view.CheckableLinearLayout>
diff --git a/core/res/res/layout/media_route_list_item_collapse_group.xml b/core/res/res/layout/media_route_list_item_collapse_group.xml
deleted file mode 100644
index 323e24d..0000000
--- a/core/res/res/layout/media_route_list_item_collapse_group.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content"
-             android:background="?android:attr/selectableItemBackground">
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="?android:attr/listPreferredItemHeightSmall"
-        android:background="#19ffffff"
-        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-        android:gravity="center_vertical">
-
-        <TextView android:layout_width="0dp"
-                  android:layout_height="wrap_content"
-                  android:layout_weight="1"
-                  android:singleLine="true"
-                  android:ellipsize="marquee"
-                  android:text="@string/media_route_chooser_grouping_done"
-                  android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/ic_media_group_collapse"
-            android:scaleType="center" />
-
-    </LinearLayout>
-</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/media_route_list_item_section_header.xml b/core/res/res/layout/media_route_list_item_section_header.xml
deleted file mode 100644
index 949635f..0000000
--- a/core/res/res/layout/media_route_list_item_section_header.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content"
-             android:paddingTop="16dp">
-    <TextView
-        android:id="@android:id/text1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:background="#19ffffff"
-        android:textStyle="bold"
-        android:textAllCaps="true"
-        android:gravity="center_vertical"
-        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-        android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-        android:minHeight="24dp"
-        />
-</FrameLayout>
diff --git a/core/res/res/layout/media_route_list_item_top_header.xml b/core/res/res/layout/media_route_list_item_top_header.xml
deleted file mode 100644
index 0c49b24..0000000
--- a/core/res/res/layout/media_route_list_item_top_header.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@android:id/text1"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:textAppearance="?android:attr/textAppearanceSmall"
-    android:background="#19ffffff"
-    android:textStyle="bold"
-    android:textAllCaps="true"
-    android:gravity="center_vertical"
-    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:minHeight="24dp"
-/>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b27ac62..0358de3 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n VPN-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind aan \'n muurpapier"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n muurpapier te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"koppel aan \'n afstandskerm"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Dit laat die houer toe om aan die top-koppelvlak van \'n afstandskerm te koppel. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind aan \'n legstukdiens"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Dit laat die houer toe om aan die topvlak-koppelvlak van \'n legstuk-diens te bind. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"skakel met \'n toestel-admin"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Stelsel"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadlose skerm"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Koppel aan toestel"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Saai skerm uit na toestel"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Soek tans vir toestelle…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Instellings"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Ontkoppel"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Skandeer tans..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Koppel tans..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Beskikbaar"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Oorlegger #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", veilig"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Draadlose skerm is gekoppel"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Hierdie skerm word op \'n ander toestel gewys"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Skerm word tans uitgesaai"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Koppel tans aan <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Skerm word tans uitgesaai"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Gekoppel aan <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Ontkoppel"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Het jy die patroon vergeet?"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 1f9599d..1e320e2 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -269,7 +269,7 @@
     <string name="permdesc_sendSms" msgid="7094729298204937667">"መተግበሪያው የኤስ.ኤም.ኤስ. መልዕክቶችን እንዲልክ ይፈቅድለታል። ይህ ያልተጠበቁ ወጪዎችን ሊያስከትል ይችላል። ተንኮል አዘል መተግበሪያዎች ያላንተ ማረጋገጫ መልዕክቶችን በመላክ ገንዘብ ሊያስወጡህ ይችላሉ።"</string>
     <string name="permlab_sendRespondViaMessageRequest" msgid="8713889105305943200">"የበመልዕክት-በኩል-ምላሽ-ስጥ ክስተቶችን ይላኩ"</string>
     <string name="permdesc_sendRespondViaMessageRequest" msgid="7107648548468778734">"መተግበሪያው ሌሎች የመልዕክት መላኪያ መተግበሪያዎች ለመጪ ጥሪዎች በመልዕክት-በኩል-ምላሽ-መስጠት ስራን እንዲይዙ ጥያቄዎች እንዲልክላቸው ያስችለዋል።"</string>
-    <string name="permlab_readSms" msgid="8745086572213270480">"የጽሑፍ መልዕክቶችህን አንብብ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
+    <string name="permlab_readSms" msgid="8745086572213270480">"የጽሑፍ መልዕክቶችዎን ያንብቡ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"መገለጫው በጡባዊ ቱኮህ ወይም በSIM ካርድህ የተከማቹ የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልእክቶች እንዲያነብ ይፈቅድለታል።"</string>
     <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"መገለጫው በስልክህ ወይም በSIM ካርድህ የተከማቹ የኤስ.ኤም.ኤስ. መልእክቶችን እንዲያነብ ይፈቅድለታል። ይህ መተግበሪያው ይዘት ወይም ሚስጥራዊነትን ከግምት ሳያስገባ ሁሉንም የኤስ.ኤም.ኤስ. መልእክቶች እንዲያነብ ይፈቅድለታል።"</string>
     <string name="permlab_writeSms" msgid="3216950472636214774">"የጽሑፍ መልዕክቶችህን አርትዕ (ኤስ.ኤም.ኤስ. ወይም ኤም.ኤም.ኤስ.)"</string>
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"የVPN ግልጋሎትን ወደ ከፍተኛ-ደረጃ በየነ ገጽ ለማሳር ለመያዣው ይፈቅዳሉ፡፡ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"በልጣፍ ጠርዝ"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ከአንድ የርቀት ማሳያ ጋር ይጠርዛል"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ፍርግም አገልግሎት ለመጠረዝ  ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ከመሣሪያ አስተዳደር ጋር ተገናኝ"</string>
@@ -498,9 +500,9 @@
     <string name="permdesc_mediaContentControl" msgid="1637478200272062">"መተግበሪያው የሚዲያ መልሰህ አጫውትን እንዲቆጣጠር እና የሚዲያ መረጃውን (ርእስ፣ ደራሲ...) እንዲደርስ ይፈቅድለታል።"</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"የድምፅ ቅንብሮችን ለውጥ"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"መተግበሪያው አንደ የድምጽ መጠን እና ለውጽአት የትኛውን የድምጽ ማጉያ ጥቅም ላይ እንደዋለ የመሳሰሉ ሁለንተናዊ የድምጽ ቅንብሮችን እንዲያስተካክል ይፈቅድለታል።"</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"ኦዲዮ ቅዳ"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"ኦዲዮ ይቅዱ"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"መተግበሪያው ድምጽን በማይክሮፎን እንዲቀዳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ያላንተ ማረጋገጫ በማንኛውም ጊዜ ድምጽ እንዲቀዳ ይፈቅድለታል።"</string>
-    <string name="permlab_camera" msgid="3616391919559751192">"ፎቶዎች እና ቪዲዮዎች አንሳ"</string>
+    <string name="permlab_camera" msgid="3616391919559751192">"ፎቶዎች እና ቪዲዮዎች ያንሱ"</string>
     <string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ካሜራው ስራ ላይ ሲሆን የማስተላለፍ አመልካች ኤል ኢ ዲን ያሰናክሉ"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ቀድሞ የተጫነ የስርዓት መተግበሪያ ካሜራውን አመላካች ኤል ኢ ዲ እንዳይጠቀም እንዲያሰናክል ያስችለዋል።"</string>
@@ -583,12 +585,12 @@
     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">" የስልኩን ሰዓት መለወጥ ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_accountManagerService" msgid="4829262349691386986">"እንደ አውርድአዸራጅአገልግሎት"</string>
     <string name="permdesc_accountManagerService" msgid="1948455552333615954">" ወደ መለያ አረጋጋጮች ጥሪ ለማድረግ ለመተግበሪያ ይፈቅዳሉ።"</string>
-    <string name="permlab_getAccounts" msgid="1086795467760122114">"መሣሪያው ላይ ያሉ መለያዎችን አግኝ"</string>
+    <string name="permlab_getAccounts" msgid="1086795467760122114">"መሣሪያው ላይ ያሉ መለያዎችን ያግኙ"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"መተግበሪያው በጡባዊ ተኮው የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"መተግበሪያው በስልኩ የሚታወቁትን መለያዎች ዝርዝር እንዲያገኝ ይፈቅድለታል። ይህ በጫንዋቸው ማናቸውም መተግበሪያዎች የተፈጠሩ መለያዎችን ሊያጠቃልል ይችላል።"</string>
     <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"መለያዎችን ፍጠርና የይለፍ ቃላትን አስቀምጥ"</string>
     <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"የመለያ አረጋጋጭ መለያ መናጅ ችሎታን ለመጠቀም፣ መለያ መፍጠር እና የይለፍ ቃሎችን ለማግኘት እና ለማቀናጀት አክሎ ለመተግበሪያው ይፈቅዳሉ ።"</string>
-    <string name="permlab_manageAccounts" msgid="4983126304757177305">"መለያዎችን አክል ወይም አስወግድ"</string>
+    <string name="permlab_manageAccounts" msgid="4983126304757177305">"መለያዎችን ያክሉ ወይም ያስወግዱ"</string>
     <string name="permdesc_manageAccounts" msgid="8698295625488292506">"መለያዎችን እንደ ማከል እና ማስወገድ ክወናዎችን እና የይለፍ ቃልን መሰረዝ ለማከናወን ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_useCredentials" msgid="235481396163877642">"በመሣሪያው ላይ ያሉ መለያዎችን ይጠቀሙ"</string>
     <string name="permdesc_useCredentials" msgid="7984227147403346422">"የማረጋገጫ የምስጋና የምስክር ወረቀትን ለመጠየቅ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
@@ -643,7 +645,7 @@
     <string name="permdesc_readDictionary" msgid="659614600338904243">"መተግበሪያው ተጠቃሚው በተጠቃሚው መዝገበ-ቃላት አከማችቷቸው ሊሆኑ የሚችሉ ሁሉንም ቃላት፣ ስሞችና ሐረጋት እንዲያነባቸው ይፈቅድለታል።"</string>
     <string name="permlab_writeDictionary" msgid="2183110402314441106">"በተጠቃሚ በተገለጸ መዝገበ ቃላት ላይ ቃላትን ያክላል"</string>
     <string name="permdesc_writeDictionary" msgid="8185385716255065291">"በተጠቃሚ መዝገበ ቃላት ውስጥ አዲስ ቃል እንዲጽፍ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
-    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"የUSB ማከማቻህን ይዘቶች አንብብ"</string>
+    <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"የUSB ማከማቻዎን ይዘቶች ያንብቡ"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"የSD ካርድህን ይዘቶች አንብብ"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"መተግበሪያው የእርስዎ USB ማከማቻ ይዘቶችን እንዲያነብ ያስችለዋል።"</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"መተግበሪያው የእርስዎ SD ካርድ ይዘቶችን እንዲያነብ ያስችለዋል።"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ስርዓት"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"የብሉቱዝ ድምጽ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ገመድ አልባ ማሳያ"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"ተከናውኗል"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"የሚዲያ ውጽዓት"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"ከመሳሪያ ጋር ያገናኙ"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ማያ ገጽን ወደ መሣሪያ ይውሰዱ"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"መሳሪያዎችን በመፈለግ ላይ…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ቅንብሮች"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ግንኙነት አቋርጥ"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"በመቃኘት ላይ..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"በማገናኘት ላይ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"የሚገኙ"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ተደራቢ #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>፦ <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>፣ <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"፣ የተጠበቀ"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"ገመድ አልባ ማሳያ ተገናኝቷል"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"ይህ ማያ ገጽ በሌላ መሣሪያ ላይ እያሳየ ነው"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"ማያ ገጽን በመውሰድ ላይ"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"ከ<xliff:g id="NAME">%1$s</xliff:g> ጋር በመገናኘት ላይ"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"ማያ ገጽን በመውሰድ ላይ"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"ከ<xliff:g id="NAME">%1$s</xliff:g> ጋር ተገናኝቷል"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"ግንኙነት አቋርጥ"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"የአደጋ ጊዜ ጥሪ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ስርዓተ ጥለቱን እርሳ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index ab03375..18296ea 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"‏للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الشبكة الظاهرية الخاصة (VPN). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"الالتزام بخلفية ما"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"الربط بالشاشة عن بُعد"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الأداة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"التفاعل مع مشرف الجهاز"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"النظام"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"عرض شاشة لاسلكي"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"تم"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"الاتصال بجهاز"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"بث الشاشة على الجهاز"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"جارٍ البحث عن الأجهزة…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"الإعدادات"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"قطع الاتصال"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"جارٍ الفحص..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"جارٍ الاتصال..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"متاح"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"المركب #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"‏<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>، <xliff:g id="DPI">%4$d</xliff:g> نقطة لكل بوصة"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"آمن"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"تم التوصيل بشاشة لاسلكية"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"يتم عرض هذه الشاشة على جهاز آخر"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"جارٍ بث الشاشة"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"جارٍ الاتصال بـ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"جارٍ بث الشاشة"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"متصل بـ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"قطع الاتصال"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"الاتصال بالطوارئ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"نسيت النقش"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 00a77a3..a0dd5d8 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -396,6 +396,10 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы VPN вышэйшага ўзроўню. Не патрэбна для звычайных прыкладанняў."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"прывязаць да шпалер"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дазваляе ўладальніку ўсталёўваць прывязку да інтэрфейсу шпалер верхняга ўзроўню. Не патрабуецца для звычайных прыкладанняў."</string>
+    <!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
+    <skip />
+    <!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
+    <skip />
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прывязаць да службы віджэту"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню службы віджэта. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"узаемадзейнічаць з адміністратарам прылады"</string>
@@ -1536,8 +1540,15 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Сістэма"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Бесправадны дысплей"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Гатова"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Мультымедыйны выхад"</string>
+    <!-- no translation found for media_route_chooser_title (1751618554539087622) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_searching (4776236202610828706) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_extended_settings (87015534236701604) -->
+    <skip />
+    <!-- no translation found for media_route_controller_disconnect (8966120286374158649) -->
+    <skip />
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканiраванне..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Падключэнне..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Даступна"</string>
@@ -1550,8 +1561,14 @@
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> кр. на цалю"</string>
     <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
     <skip />
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Падключаны бесправадны дысплей"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Гэты экран паказваецца на іншай прыладзе"</string>
+    <!-- no translation found for wifi_display_notification_connecting_title (9102788196896266990) -->
+    <skip />
+    <!-- no translation found for wifi_display_notification_connecting_message (5837350993752841389) -->
+    <skip />
+    <!-- no translation found for wifi_display_notification_connected_title (4118323329495921271) -->
+    <skip />
+    <!-- no translation found for wifi_display_notification_connected_message (2587209325701109715) -->
+    <skip />
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Адключыць"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Экстранны выклік"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d16796e..0d1cdaf 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за VPN. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"обвързване с тапет"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"свързване с отдалечен екран"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за приспособления. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаимодействие с администратор на устройството"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Безжичен дисплей"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Свързване с устройство"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Екран за предаване към устройството"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Търсят се устройства…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Настройки"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Прекратяване на връзката"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканира се..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Установява се връзка..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Налице"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наслагване №<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"„<xliff:g id="NAME">%1$s</xliff:g>“: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", защитено"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Безжичният дисплей е свързан"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Този екран се показва на друго устройство"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Екранът се предава"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Установява се връзка с/ъс „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Екранът се предава"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Установена е връзка с/ъс „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Прекратяване на връзката"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Спешно обаждане"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забравена фигура"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 65416f1..e0d07bf 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de VPN. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"enllaça amb un fons de pantalla"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet que el titular vinculi a la interfície de nivell superior d\'un fons de pantalla. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincula a una pantalla remota"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet que el titular es vinculi a la interfície de nivell superior d\'una pantalla remota. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincula a un servei de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet que el titular vinculi a la interfície de nivell superior d\'un servei de widget. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar amb un administrador del dispositiu"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla sense fil"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fet"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortida de contingut multimèdia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexió al dispositiu"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emissió de pantalla al dispositiu"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"S\'estan cercant dispositius…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Configuració"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconnecta"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"S\'està cercant…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"S\'està connectant..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposa #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", segur"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"La pantalla sense fil està connectada"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Aquesta pantalla es mostra en un altre dispositiu"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Emissió de pantalla"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"S\'està connectant a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Emissió de pantalla"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connectat a <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconnecta"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Trucada d\'emergència"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patró oblidat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f4cb4d0..14d6dd5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteli navázat se na nejvyšší úroveň služby VPN. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"vazba na tapetu"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní tapety. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"připojit se ke vzdálenému displeji"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteli připojit se k vysokoúrovňovému rozhraní vzdáleného displeje. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"navázat se na službu widgetu"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteli navázat se na nejvyšší úroveň služby widgetu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovat se správcem zařízení"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrátový displej"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Připojení k zařízení"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odesílání obsahu obrazovky do zařízení"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Vyhledávání zařízení…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavení"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Odpojit"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Vyhledávání…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Připojování…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Dostupná"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Překryvná vrstva č. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", zabezpečené"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezdrátový displej je připojen"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tato obrazovka se zobrazuje v jiném zařízení"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Odesílání obsahu obrazovky"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Připojování k obrazovce <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Odesílání obsahu obrazovky"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Připojeno k obrazovce <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojit"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Tísňové volání"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zapomenuté gesto"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 997837a..0219a0f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Tillader, at brugeren forpligter sig til en VPN-tjenestes grænseflade på øverste niveau. Bør aldrig være nødvendigt i almindelige apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"forpligt til et tapet"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Tillader, at indehaveren kan binde en baggrunds grænseflade på øverste niveau. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind til en ekstern skærm"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Tillader, at brugeren kan foretage en binding til grænsefladens øverste niveau på en ekstern skærm. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"forpligt til en widgettjeneste"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Tillader, at brugeren kan forpligte sig til en grænseflade for en widgettjeneste på øverste niveau. Bør aldrig være nødvendigt til almindelige apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikere med en enhedsadministrator"</string>
@@ -1119,7 +1121,7 @@
     <string name="loading" msgid="7933681260296021180">"Indlæser…"</string>
     <string name="capital_on" msgid="1544682755514494298">"TIL"</string>
     <string name="capital_off" msgid="6815870386972805832">"FRA"</string>
-    <string name="whichApplication" msgid="4533185947064773386">"Fuldfør handling ved hjælp af"</string>
+    <string name="whichApplication" msgid="4533185947064773386">"Brug"</string>
     <string name="whichHomeApplication" msgid="4616420172727326782">"Vælg en startsideapp"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ryd standard i Systemindstillinger &gt; Apps &gt; Downloadet."</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skærm"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Udfør"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieudgang"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Opret forbindelse til enheden"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Send skærm til enhed"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søger efter enheder…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Indstillinger"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Afbryd forbindelsen"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Søger..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Opretter forbindelse..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tilgængelig"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlejring nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sikker"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Der er tilsluttet en trådløs skærm"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Denne skærm vises på en anden enhed"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Skærm sendes"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Der oprettes forbindelse til <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Skærm sendes"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Forbundet til <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Afbryd forbindelsen"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødopkald"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Glemt mønster"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4f40d72..34f28fc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ermöglicht dem Halter, sich an die Oberfläche eines VPN-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"An einen Hintergrund binden"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ermöglicht dem Halter, sich an die Oberfläche eines Hintergrunds auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"An Remote-Display binden"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ermöglicht dem Halter, sich an die Oberfläche eines Remote-Displays auf oberster Ebene zu binden. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"An einen Widget-Dienst binden"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ermöglicht dem Halter, sich an die Oberfläche eines Widget-Dienstes auf oberster Ebene zu binden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Interaktion mit einem Geräteadministrator"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-Audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Kabellose Übertragung (WiDi)"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fertig"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medienausgabe"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Mit Gerät verbinden"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Bildschirm auf Gerät übertragen"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Geräte werden gesucht…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Einstellungen"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Verbindung trennen"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Wird gescannt..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Verbindung wird hergestellt..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Verfügbar"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay-Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sicher"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Kabellose Übertragung (WiDi) ist aktiviert."</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Dieser Bildschirm wird auf einem anderen Gerät angezeigt."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Bildschirm wird übertragen"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Verbindung mit <xliff:g id="NAME">%1$s</xliff:g> wird hergestellt."</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Bildschirm wird übertragen"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Verbunden mit <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbindung trennen"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Notruf"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Muster vergessen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6a34a6a..ee98ceb 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας Vpn. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"δέσμευση σε ταπετσαρία"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"μεταφορά σε μια απομακρυσμένη οθόνη"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας γραφικών στοιχείων. Δεν απαιτείται για κανονικές εφαρμογές."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"επικοινωνία με έναν διαχειριστή συσκευής"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Σύστημα"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ήχος Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Ασύρματη οθόνη"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Τέλος"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Έξοδος μέσων"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Σύνδεση με τη συσκευή"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Μετάδοση οθόνης σε συσκευή"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Αναζήτηση συσκευών…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ρυθμίσεις"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Αποσύνδεση"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Σάρωση…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Σύνδεση…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Διαθέσιμη"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Επικάλυψη #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ασφαλές"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Έχει συνδεθεί ασύρματη οθόνη"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Αυτή η οθόνη εμφανίζεται σε μια άλλη συσκευή"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Μετάδοση οθόνης"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Γίενται σύνδεση με το <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Μετάδοση οθόνης"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Συνδέθηκε με το <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Αποσύνδεση"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Κλήσεις επείγουσας ανάγκης"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ξεχάσατε το μοτίβο"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b706ee8..d2c53cc 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Done"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Settings"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Disconnect"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Scanning..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connecting..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Wireless display is connected"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"This screen is showing on another device"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Casting screen"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connecting to <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Casting screen"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connected to <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnect"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b706ee8..d2c53cc 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Allows the holder to bind to the top-level interface of a Vpn service. Should never be needed for normal apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bind to wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for normal applications."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind to a remote display"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Allows the holder to bind to the top-level interface of a remote display. Should never be needed for normal apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind to a widget service"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Allows the holder to bind to the top-level interface of a widget service. Should never be needed for normal apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interact with device admin"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Done"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Connect to device"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Cast screen to device"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Searching for devices…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Settings"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Disconnect"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Scanning..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connecting..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Wireless display is connected"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"This screen is showing on another device"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Casting screen"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connecting to <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Casting screen"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connected to <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnect"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 165b6a6..114f6f5 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite al titular vincularse a la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a un fondo de pantalla"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deben utilizar este permiso."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vincular a una pantalla remota"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite al propietario vincularse a la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a un servicio de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar al dispositivo"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir pantalla a dispositivo"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Configuración"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconectar"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Examinando..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", segura"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Se conectó la pantalla inalámbrica"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Transmitiendo pantalla"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Estableciendo conexión con <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Transmitiendo pantalla"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Se estableció conexión con <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Realizar llamada de emergencia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c38a075..f758989 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite enlazar con la interfaz de nivel superior de un servicio de VPN. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"enlazar con un fondo de pantalla"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite enlazar con la interfaz de nivel superior de un fondo de pantalla. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"enlazar a una pantalla remota"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite enlazar con la interfaz de nivel superior de una pantalla remota. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"enlazar con un servicio de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite enlazar con la interfaz de nivel superior de un servicio de widget. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con el administrador de un dispositivo"</string>
@@ -788,7 +790,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo!"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Conversaciones"</string>
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Pantalla inalámbrica"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fin"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar a dispositivo"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Enviar pantalla a dispositivo"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Buscando dispositivos…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ajustes"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconectar"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Analizando..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", seguro"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Pantalla inalámbrica conectada"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Esta pantalla se muestra en otro dispositivo."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Enviando pantalla"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Conectando a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Enviando pantalla"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Conectado a <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Has olvidado el patrón?"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 5f05ac2..39523ef 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda VPN-teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"taustapildiga sidumine"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"kaugekraaniga sidumine"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lubab omanikul siduda rakenduse kaugekraani ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lubab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"seadme administraatoriga suhtlemine"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Süsteem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Juhtmeta ekraan"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Seadmega ühendamine"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekraanikuva ülekandmine seadmesse"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Seadmete otsimine …"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Seaded"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Katkesta ühendus"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Skaneering ..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Ühendan..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Saadaval"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Ülekate nr .<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", turvaline"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Juhtmeta ekraaniühendus on loodud"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ekraan on näha teises seadmes"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Ekraanikuva ülekandmine"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Ühendamine ekraaniga <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Ekraanikuva ülekandmine"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Ühendatud ekraaniga <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Katkesta ühendus"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Hädaabikõne"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unustasin mustri"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index baa11fa..93a8eec 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"‏به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس Vpn متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"پیوند شده به تصویر زمینه"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"‏به دارنده اجازه می‎دهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامه‎های معمولی هرگز به این ویژگی نیاز ندارند."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"اتصال به نمایشگر راه دور"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده ام‍ک‍ان می‌دهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامه‌های عادی لازم باشد."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"به دارنده اجازه می‌دهد که به رابط سطح بالای سرویس ابزارک متصل شود. هرگز برای برنامه‌های معمولی مورد نیاز نیست."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"تعامل با یک سرپرست دستگاه"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"سیستم"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوث‌های صوتی"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"صفحه نمایش بی‌سیم"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"برقراری ارتباط با دستگاه"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"فرستادن صفحه نمایش به دستگاه"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"در حال جستجو برای دستگاه‌ها..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"تنظیمات"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"قطع ارتباط"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"در حال اسکن کردن…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"درحال اتصال…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"در دسترس"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"همپوشانی #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"، امن"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"نمایشگر بی‌سیم متصل است"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"این صفحه در حال نمایش در دستگاه دیگری است"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"درحال فرستادن صفحه نمایش"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"درحال اتصال به <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"درحال فرستادن صفحه نمایش"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"به <xliff:g id="NAME">%1$s</xliff:g> متصل شد"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"قطع اتصال"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"تماس اضطراری"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"الگو را فراموش کرده‌اید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3718ccc..e4d4e3e 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Antaa sovelluksen sitoutua VPN-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sido taustakuvaan"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Antaa sovelluksen sitoutua taustakuvan ylätason käyttöliittymään. Ei tavallisten sovellusten käyttöön."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"etänäyttöön sitoutuminen"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Antaa sovelluksen sitoutua etänäytön ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sitoudu widget-palveluun"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Antaa sovelluksen sitoutua widget-palvelun ylemmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunikoi laitteen järjestelmänvalvojan kanssa"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Järjestelmä"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ääni"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Langaton näyttö"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Median äänentoisto"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Yhdistä laitteeseen"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lähetä näyttö laitteeseen"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Etsitään laitteita…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Asetukset"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Katkaise yhteys"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Etsitään..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Yhdistetään..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Käytettävissä"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Peittokuva # <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", suojattu"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Langaton näyttö on yhdistetty"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tämä ruutu näkyy toisella laitteella"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Lähetetään näyttöä"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Yhdistetään näyttöön <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Lähetetään näyttöä"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Yhdistetty näyttöön <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Katkaise yhteys"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Hätäpuhelu"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unohtunut kuvio"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index bbfaad7..7c11f9a 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service RPV. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"se fixer à un fond d\'écran"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"lier à un écran distant"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un écran distant. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"s\'associer à un service de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur d\'un périphérique"</string>
@@ -788,7 +790,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Conversations"</string>
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminé"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Diffuser l\'écran sur l\'appareil"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Paramètres"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Déconnecter"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Analyse en cours..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connexion en cours..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposition n° <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sécurisé"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"L\'affichage sans fil est connecté."</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Cet écran s\'affiche sur un autre appareil."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Connexion à l\'écran en cours"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connexion au réseau <xliff:g id="NAME">%1$s</xliff:g> en cours…"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Diffusion de l\'écran en cours"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connecté à <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Déconnecter"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a6d7687..04a55f2 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service VPN. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"Se fixer sur un fond d\'écran"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un fond d\'écran. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"s\'associer à un écran à distance"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permettre à l\'application autorisée de s\'associer à l\'interface de niveau supérieur d\'un écran à distance. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associer à un service widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service widget. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Système"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Affichage sans fil"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Connexion à l\'appareil"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Diffuser l\'écran sur l\'appareil"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Recherche d\'appareils en cours…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Paramètres"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Déconnecter"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Analyse en cours..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connexion en cours..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponible"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposition n° <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sécurisé"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"L\'affichage sans fil est connecté."</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Cet écran s\'affiche sur un autre appareil."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Diffusion de l\'écran en cours"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Connexion à <xliff:g id="NAME">%1$s</xliff:g> en cours…"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Diffusion de l\'écran en cours"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Connecté à <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Déconnecter"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 59ac55c..2650108 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"रिमोट डिस्प्ले से आबद्ध करें"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्‍तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"धारक को किसी विजेट सेवा के शीर्ष-स्‍तर इंटरफ़ेस से आबद्ध होने देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"किसी उपकरण व्‍यवस्‍थापक के साथ सहभागिता करें"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्‍टम"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस प्रदर्शन"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"उपकरण से कनेक्ट करें"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"स्क्रीन को उपकरण में कास्ट करें"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"उपकरण खोजे जा रहे हैं…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"सेटिंग"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"डिस्कनेक्ट करें"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"स्‍कैन कर रहा है..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"कनेक्ट हो रहा है..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"उपलब्ध"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ओवरले #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", सुरक्षित"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"वायरलेस डिस्प्ले कनेक्ट है"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"यह स्क्रीन अन्य उपकरण पर दिखाई दे रही है"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"स्क्रीन कास्ट हो रही है"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> से कनेक्ट हो रहा है"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"स्क्रीन कास्ट हो रही है"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> से कनेक्ट है"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"डिस्कनेक्ट करें"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"आकार भूल गए"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2b04e02..829c03d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Nositelju omogućuje vezanje uz sučelje najviše razine VPN usluge. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezano s pozadinskom slikom"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Nositelju omogućuje povezivanje sa sučeljem pozadinske slike najviše razine. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"vezanje uz udaljeni zaslon"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Nositelju omogućuje vezanje uza sučelje najviše razine udaljenog zaslona. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vezanje na uslugu widgeta"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Nositelju omogućuje vezanje uz sučelje najviše razine usluge widgeta. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s administratorom uređaja"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sustav"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični prikaz"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezivanje s uređajem"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Emitiranje zaslona na uređaj"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Traženje uređaja…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Postavke"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Prekini vezu"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Skeniranje..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Povezivanje..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Dostupno"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Preklapanje br. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sigurno"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bežični je prikaz povezan"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ovaj se zaslon prikazuje na nekom drugom uređaju"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Emitiranje zaslona"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Povezivanje sa zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Emitiranje zaslona"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Povezan sa zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Isključi"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Hitan poziv"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravili ste obrazac"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 71f6bdc..4c9f400 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lehetővé teszi a használó számára, hogy csatlakozzon egy VPN-szolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"összekapcsolás háttérképpel"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lehetővé teszi, hogy a tulajdonos kötelezővé tegye egy háttérkép legfelső szintű felületét. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"csatlakozás egy távoli kijelzőhöz"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lehetővé teszi a használó számára, hogy csatlakozzon egy távoli kijelző legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"csatlakozás modulszolgáltatáshoz"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lehetővé teszi a használó számára, hogy csatlakozzon egy modulszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"az eszközkezelő használata"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Rendszer"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Vezeték nélküli kijelző"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Csatlakozás adott eszközhöz"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Képernyő átküldése az eszközre"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Eszközkeresés…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Beállítások"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Leválasztás"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Keresés..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Kapcsolódás..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Elérhető"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>. fedvény"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> képpont"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", biztonságos"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Vezeték nélküli kijelző csatlakoztatva"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ez a kijelző megjelenítést végez egy másik eszközön"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Képernyő átküldése…"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Csatlakozás a következőhöz: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Képernyő átküldése…"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Csatlakozva a következőhöz: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Szétkapcsol"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Segélyhívás"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Elfelejtett minta"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index f5ed539..85eedba 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Թույլ է տալիս սեփականատիրոջը միանալ Vpn ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"միանալ պաստառին"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Թույլ է տալիս սեփականատիրոջը միանալ պաստառի վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Թույլ է տալիս սեփականատիրոջը միանալ վիջեթ ծառայության վերին մակարդակի ինտերֆեյսին: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"փոխգործակցել սարքի կառավարչի հետ"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Համակարգ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ի ձայնանյութ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Անլար էկրան"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Կատարված է"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Մեդիա արտածում"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Միանալ սարքին"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Հեռարձակել էկրանը սարքի վրա"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Որոնվում են սարքեր..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Կարգավորումներ"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Անջատել"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Սկանավորում..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Միանում է..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Հասանելի է"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Վերածածկ #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> կմվ"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", անվտանգ"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Անլար ցուցադրումը կապակցված է"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Այս էկրանը ցուցադրվում է այլ սարքում"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Էկրանի հեռարձակում"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Միանում է <xliff:g id="NAME">%1$s</xliff:g>-ին"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Էկրանը հեռարձակվում է"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Միացված է <xliff:g id="NAME">%1$s</xliff:g>-ին"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Անջատել"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Արտակարգ իրավիճակի հեռախոսազանգ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Մոռացել եմ սխեման"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d6d91fb..633621a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan Vpn. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"mengikat ke wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu wallpaper. Tidak pernah diperlukan oleh apl normal."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"mengikat ke layar jarak jauh"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Mengizinkan pemegang mengikat ke antarmuka tingkat atas dari layar jarak jauh. Tidak pernah diperlukan untuk aplikasi normal."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"mengikat ke layanan widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Mengizinkan pemegang mengikat antarmuka tingkat tinggi dari suatu layanan widget. Tidak pernah diperlukan oleh apl normal."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan admin perangkat"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Layar nirkabel"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Keluaran media"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambungkan ke perangkat"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmisi layar ke perangkat"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Menelusuri perangkat…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Setelan"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Putuskan sambungan"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Memindai..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Hamparan #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", aman"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Layar nirkabel tersambung"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Layar ini ditampilkan di perangkat lain"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Transmisi layar"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Menyambung ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Transmisi layar"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Tersambung ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Putuskan sambungan"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan darurat"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Pola?"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 88d69de..6bae95b 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Consente l\'associazione all\'interfaccia principale di un servizio VPN. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"associazione a sfondo"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Consente l\'associazione di uno sfondo all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"collega a un display remoto"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un display remoto. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"associazione a un servizio widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Consente l\'associazione all\'interfaccia principale di un servizio widget. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interazione con un amministratore dispositivo"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualizzazione wireless"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fine"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Uscita media"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Connetti al dispositivo"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Trasmetti schermo al dispositivo"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ricerca di dispositivi in corso…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Impostazioni"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Disconnetti"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Ricerca in corso..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Connessione..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponibile"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay n. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", opzione sicura"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Il display wireless è connesso"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Questa schermata è mostrata su un altro dispositivo"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Trasmissione schermo"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Collegamento a <xliff:g id="NAME">%1$s</xliff:g> in corso"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Trasmissione schermo attiva"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Collegato a <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Disconnetti"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Chiamata di emergenza"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Sequenza dimenticata"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8dcdac5..1d42f65 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"‏מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שירות VPN. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"קשור לטפט"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"איגוד לצג מרוחק"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"‏הכפפה לשירות Widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"‏מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של שירות Widget. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"קיים אינטראקציה עם מנהל המכשיר"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"מערכת"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"‏אודיו Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"צג אלחוטי"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"סיום"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"פלט מדיה"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"התחברות למכשיר"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"העברת מסך אל מכשיר"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"מחפש מכשירים…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"הגדרות"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"התנתק"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"סורק..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"מתחבר..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"זמין"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"שכבת על #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"‏<xliff:g id="NAME">%1$s</xliff:g>: ‎<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>‎, ‏<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", מאובטח"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"מסך אלחוטי מחובר"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"מסך זה מוצג במכשיר אחר"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"העברת מסך מתבצעת"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"מתחבר אל <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"העברת מסך מתבצעת"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"מחובר אל <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"נתק"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"שיחת חירום"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"שכחת את הקו"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 0dc0a30..559d53f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"VPNサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"壁紙にバインド"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"リモートディスプレイへのバインド"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ウィジェットサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"デバイス管理者との通信"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"システム"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ワイヤレスディスプレイ"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"端末に接続"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"端末への画面のキャスト"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"端末を検索しています…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"設定"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"接続を解除"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"スキャン中..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"接続中..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"利用できます"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"オーバーレイ第<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>、<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"、セキュア"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"ワイヤレスディスプレイが接続されています"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"この画面は別の端末で表示されています"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"画面のキャスト中"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g>に接続しています"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"画面のキャスト中"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g>に接続しました"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"切断"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急通報"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"パターンを忘れた場合"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index efc85ba..7f4dc90 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"აპს შეეძლება Vpn სერვისის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ფონზე მიჭედება"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"მფლობელს შეეძლება ფონის ზედა დონის ინტერფეისთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"აპს შეეძლება ზედა დონის ინტერფეისის ვიჯეტთან დაკავშირება. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"მოწყობილობის ადმინთან ინტერაქცია"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"სისტემა"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth აუდიო"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"უსადენო ეკრანი"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"დასრულდა"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"მედია გამომავალი"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"მოწყობილობასთან დაკავშირება"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ეკრანის მოწყობილობაზე გადაცემა"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"მოწყობილობების ძიება…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"პარამეტრები"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"კავშირის გაწყვეტა"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"სკანირება..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"დაკავშირება..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"ხელმისაწვდომი"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"გადაფარვა #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", დაცული"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"უსადენო ეკრანი დაკავშირებულია"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"გამოსახულება გადაეცემა სხვა მოწყობილობას"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"მიმდინარეობს ეკრანის გადაცემა"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g>-თან დაკავშირება"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"მიმდინარეობს ეკრანის გადაცემა"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"დაკავშირებულია <xliff:g id="NAME">%1$s</xliff:g>-თან"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"კავშირის გაწყვეტა"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"გადაუდებელი დახმარების ზარი"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"დაგავიწყდათ ნიმუში"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 1014da4..3bf648b 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម Vpn ។​ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ចង​ទៅ​ផ្ទាំង​រូបភាព"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ឲ្យ​ម្ចាស់​ចង​ចំណុចប្រទាក់​កម្រិត​កំពូល​នៃ​ផ្ទាំង​រូបភាព។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់​ទៅ​ការ​បង្ហាញ​ពី​ចម្ងាយ"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាត​ឲ្យ​ម្ចាស់​ភ្ជាប់​​ទៅ​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​ការ​បង្ហាញ​ពី​ចម្ងាយ។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចង​សេវា​កម្ម​ធាតុ​ក្រាហ្វិក"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ឲ្យ​ម្ចាស់​ចង​ចំណុច​ប្រទាក់​កម្រិត​កំពូល​នៃ​សេវាកម្ម​ធាតុ​ក្រាហ្វិក។ មិន​គួរ​​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ទាក់ទង​ជា​មួយ​អ្នកគ្រប់គ្រង​ឧបករណ៍"</string>
@@ -788,7 +790,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"ការ​ជជែក"</string>
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ប្រព័ន្ធ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"សំឡេង​ប៊្លូធូស"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"បង្ហាញ​បណ្ដាញ​ឥត​ខ្សែ"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"រួចរាល់"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"លទ្ធផល​មេឌៀ"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"ភ្ជាប់​ឧបករណ៍"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ចាត់​ថ្នាក់​អេក្រង់​ទៅ​ឧបករណ៍"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"កំពុង​ស្វែងរក​ឧបករណ៍..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ការ​កំណត់"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ផ្ដាច់"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"កំពុង​វិភាគ​រក…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"កំពុង​​​ភ្ជាប់​…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"ទំនេរ"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"#<xliff:g id="ID">%1$d</xliff:g> ត្រួត​គ្នា"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", សុវត្ថិភាព"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"បាន​ភ្ជាប់​ការ​បង្ហាញ​បណ្ដាញ​ឥត​ខ្សែ"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"អេក្រង់​នេះ​បង្ហាញ​លើ​ឧបករណ៍​ផ្សេង"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"ចាត់​ថ្នាក់​អេក្រង់"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"កំពុង​តភ្ជាប់​ទៅ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"ចាត់​ថ្នាក់​អេក្រង់"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"តភ្ជាប់​ទៅ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"ផ្ដាច់"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"ការ​ហៅ​ពេល​អាសន្ន"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ភ្លេច​​លំនាំ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 2240069..d5eb619 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"권한을 가진 프로그램이 VPN 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"배경화면 연결"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"원격 디스플레이에 연결"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"권한을 가진 프로그램이 위젯 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"기기 관리자와 상호 작용"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"시스템"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"무선 디스플레이"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"기기에 연결"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"기기로 화면 전송"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"기기 검색 중…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"설정"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"연결 해제"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"검색 중..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"연결 중..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"사용 가능"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>번째 오버레이"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", 보안"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"무선 디스플레이가 연결되었습니다."</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"이 화면은 다른 기기에서 표시되고 있습니다."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"화면 전송 중"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g>에 연결 중"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"화면 전송 중"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g>에 연결됨"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"연결 해제"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"긴급 통화"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"패턴을 잊음"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index b6de941..8d88dfee9f 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບເທິງສຸດ ຂອງບໍລິການ VPN. ແອັບຯທົ່ວໄປບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ເຊື່ອມໂຍງກັບພາບພື້ນຫຼັງ"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ອະນຸຍາດໃຫ້ຜູ່ໃຊ້ເຊື່ອມໂຍງກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງພາບພື້ນຫຼັງໃດນຶ່ງ. ແອັບຯທຳມະດາບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ຜູກກັນເພື່ອສະແດງຜົນທາງໄກ."</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບອິນເຕີເຟດລະດັບສູງສຸດ ຂອງບໍລິການວິເຈັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ຕິດຕໍ່ກັບຜູ່ເບິ່ງແຍງອຸປະກອນ"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ລະບົບ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ສຽງ Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"ການສະແດງຜົນໄຮ້ສາຍ"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"ແລ້ວໆ"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"ມີເດຍເອົ້າພຸດ"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"ເຊື່ອມຕໍ່ຫາອຸປະກອນ"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ສົ່ງພາບໜ້າຈໍໄປຫາອຸປະກອນ"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"ກຳລັງຊອກຫາອຸປະກອນ..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"ການຕັ້ງຄ່າ"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ຕັດການເຊື່ອມຕໍ່"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"ກຳລັງສະແກນ..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"ກຳລັງເຊື່ອມຕໍ່..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"ສາມາດໃຊ້ໄດ້"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ການວາງຊ້ອນ #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ປອດໄພ"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"ເຊື່ອມຕໍ່ການສະແດງຜົນໄຮ້ສາຍແລ້ວ"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"ຈໍນີ້ກຳລັງສະແດງຢູ່ໃນອຸປະກອນອື່ນ"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"ກຳລັງສົ່ງພາບໜ້າຈໍ"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"ກຳລັງເຊື່ອມຕໍ່ຫາ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"ການສົ່ງພາບໜ້າຈໍ"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="NAME">%1$s</xliff:g> ແລ້ວ"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"ຢຸດການເຊື່ອມຕໍ່"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"ການໂທສຸກເສີນ"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ລືມຮູບແບບປົດລັອກ?"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c32bd9d..614bcd6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Leidžiama savininkui susisaistyti su aukščiausio lygio VPN paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"susaistyti su darbalaukio fonu"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Leidžiama savininką susaistyti su aukščiausio lygio darbalaukio fono sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"susisaistyti su nuotoliniu ekranu"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Leidžiama savininkui susisaistyti su aukščiausiojo lygio nuotolinio ekrano sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"susaistyti su valdiklio paslauga"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Leidžiama savininkui susisaistyti su aukščiausio lygio valdiklio paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"sąveikauti su įrenginio administratoriumi"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Belaidis rodymas"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Atlikta"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Prijungimas prie įrenginio"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Perduoti ekraną į įrenginį"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Ieškoma įrenginių…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nustatymai"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Atjungti"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Nuskaitoma..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Jungiama..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Pasiekiama"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Perdanga nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"„<xliff:g id="NAME">%1$s</xliff:g>“: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> tašk. colyje"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", saugu"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Prijungtas belaidis monitorius"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Šis ekranas rodomas kitame įrenginyje"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Perduodamas ekranas"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Prisijungiama prie „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Perduodamas ekranas"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Prisijungta prie „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Atjungti"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Skambutis pagalbos numeriu"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pamiršau atrakinimo piešinį"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 66a5d73..9f3cb53 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ļauj īpašniekam izveidot saiti ar VPN pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"saistīt ar tapeti"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ļauj īpašniekam piesaistīt tapetes augstākā līmeņa lietotāja saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Saites izveide ar attālu displeju"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ļauj īpašniekam izveidot saiti ar attāla displeja augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"saistīt ar logrīka pakalpojumu"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ļauj īpašniekam izveidot saiti ar logrīka pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"mijiedarboties ar ierīces administratoru"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistēma"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezvadu attēlošana"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gatavs"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Savienojuma izveide ar ierīci"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekrāna apraide uz ierīci"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Notiek ierīču meklēšana…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Iestatījumi"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Atvienot"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Notiek meklēšana..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Notiek savienojuma izveide..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Pieejams"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Pārklājums Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", drošs"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezvadu attēlošanas savienojums ir izveidots."</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Šis ekrāns tiek rādīts citā ierīcē."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Ekrāna apraidīšana"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Notiek savienojuma izveide ar: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Ekrāna apraidīšana"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Izveidots savienojums ar: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Pārtraukt savienojumu"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Ārkārtas izsaukums"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Aizmirsu kombināciju"</string>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index 886ecbe..d602c9f 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -21,22 +21,6 @@
      for different hardware and product builds. -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
-    <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
-    <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
-    <integer-array translatable="false" name="config_tether_upstream_types">
-      <item>1</item>
-      <item>4</item>
-      <item>7</item>
-      <item>9</item>
-    </integer-array>
-
-    <!-- String containing the apn value for tethering.  May be overriden by secure settings
-         TETHER_DUN_APN.  Value is a comma separated series of strings:
-         "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
-    <string translatable="false" name="config_tether_apndata">T-Mobile Tethering,pcweb.tmobile.com,,,,,,,,,310,260,,DUN</string>
-
     <!-- Configure mobile network MTU. Carrier specific value is set here.
     -->
     <integer name="config_mobile_mtu">1440</integer>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 6ce299d..252a959 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Эзэмшигч нь VPN үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ханын зурагтай холбох"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"алсын дэлгэцтэй холбогдох"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Эзэмшигч нь виджет үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"төхөөрөмжийн админтай харилцан үйлчлэх"</string>
@@ -788,7 +790,7 @@
     <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
     <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Цугларалт"</string>
+    <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
     <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Блютүүт аудио"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Утасгүй дэлгэц"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Дууссан"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Медиа гаралт"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Төхөөрөмжтэй холбох"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Дэлгэцийг төхөөрөмж рүү дамжуулах"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Төхөөрөмжүүдийг хайж байна…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Тохиргоо"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Салгах"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Скан хийж байна..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Холбогдож байна..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Боломжтой"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Давхарга #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", найдвартай"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Утасгүй дэлгэц холбогдов"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Энэ дэлгэц өөр төхөөрөмжийг харуулж байна"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Дэлгэцийг дамжуулж байна"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> руу холбогдож байна"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Дэлгэцийг дамжуулж байна"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> руу холбогдсон"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Салгах"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Яаралтай дуудлага"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Хээг мартсан"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 8203921..284837a 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan Vpn. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"terikat pada kertas dinding"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi kertas dinding. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"terikat kepada paparan jauh"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi paparan jauh. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"terikat kepada perkhidmatan widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan widget. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"berinteraksi dengan pentadbir peranti"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Paparan wayarles"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Sambung ke peranti"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Hantar skrin ke peranti"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Mencari peranti..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Tetapan"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Putuskan sambungan"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Mengimbas…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Menyambung..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tersedia"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Tindih #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", selamat"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Paparan wayarles disambungkan"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Skrin ini ditunjukkan pada peranti lain"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Menghantar skrin"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Menyambung ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Menghantar skrin"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Disambungkan ke <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Putus sambungan"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan kecemasan"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Corak"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 8aed6f1..7b77a1c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en VPN-tjeneste. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"binde til bakgrunnsbilde"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lar innehaveren binde det øverste nivået av grensesnittet til en bakgrunn. Skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"binde til ekstern skjerm"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Lar innehaveren binde seg til det øverste grensesnittnivået for ekstern skjerm. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"binde til modultjenste"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lar innehaveren binde seg til det øverste nivået av grensesnittet for en modultjeneste. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådløs skjerm"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fullført"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Koble til enheten"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Send skjermen til enheten"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Søker etter enheter …"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Innstillinger"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Koble fra"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Skanner ..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Kobler til ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tilgjengelig"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlegg #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", sikker"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Trådløs skjermdeling er tilkoblet"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Denne skjermen vises på en annen enhet"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Sender skjermen …"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Kobler til <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Sender skjermen …"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Koblet til <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Koble fra"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødnummer"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glemt mønsteret?"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5838aef..ba221cc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Staat de houder toe verbinding te maken met de hoofdinterface van een VPN-service. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"verbinden met een achtergrond"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Hiermee wordt de houder toegestaan zich te verbinden met de hoofdinterface van een achtergrond. Nooit vereist voor normale apps."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"verbinding maken met een extern display"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een extern display. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"verbinden met een widgetservice"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Hiermee wordt de houder toegestaan verbinding te maken met de hoofdinterface van een widgetservice. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systeem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadloze weergave"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gereed"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Verbinding maken met apparaat"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Scherm sturen naar apparaat"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Zoeken naar apparaten…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Instellingen"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Verbinding verbreken"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Scannen..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Verbinden..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Beschikbaar"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", beveiligd"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Draadloze weergave is aangesloten"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Dit scherm wordt op een ander apparaat weergegeven"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Scherm sturen"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Verbinden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Scherm sturen"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Verbonden met <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Verbinding verbreken"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patroon vergeten"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 847f9cc..217d2c9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi VPN. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"powiązanie z tapetą"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu tapety. Nieprzeznaczone dla zwykłych aplikacji."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"powiązanie z wyświetlaczem zdalnym"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu wyświetlacza zdalnego. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"powiązanie z usługą widżetów"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Zezwala na tworzenie powiązania z interfejsem najwyższego poziomu usługi widżetów. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wyświetlacz bezprzewodowy"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotowe"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Połącz z urządzeniem"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prezentuj ekran na urządzeniu"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Szukam urządzeń…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ustawienia"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Rozłącz"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Skanuję..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Łączę..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Dostępne"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Nakładka nr <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", bezpieczny"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Podłączony jest wyświetlacz bezprzewodowy"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ten ekran jest wyświetlany na innym urządzeniu"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Rozpoczynam prezentowanie ekranu"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Łączę z <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Trwa prezentowanie ekranu"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Połączono z <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Rozłącz"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Połączenie alarmowe"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nie pamiętam wzoru"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2aa5e9a..2d69f9c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que o titular se vincule à interface de nível superior de um serviço de VPN. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a uma imagem de fundo"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite ao titular vincular-se à interface de nível superior de uma imagem de fundo. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"associar a um ecrã remoto"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite ao detentor associar a interface de nível superior a um ecrã remoto. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vincular a um serviço de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o titular vincule a interface de nível superior de um serviço de widget. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com um administrador do dispositivo"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Visualização sem fios"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Ligar ao dispositivo"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir ecrã para o dispositivo"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"A pesquisar dispositivos…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Definições"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desligar"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"A procurar..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"A ligar..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponível"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> ppp"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", protegido"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"O Display sem fios está ligado"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Este ecrã está a ser apresentado noutro dispositivo"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"A transmitir o ecrã"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"A ligar a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"A transmitir o ecrã"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Ligado a <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desligar"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueceu-se da Sequência"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b13044f..f1ad4d7 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite que seu proprietário sujeite a interface de alto nível de um serviço de VPN. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sujeitar-se a um plano de fundo"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite que o proprietário utilize interface de nível superior de um plano de fundo. Nunca deve ser necessário para aplicativos normais."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"usar uma tela remota"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite que o proprietário use a interface de nível superior de uma tela remota. Não deve ser necessário para aplicativos comuns."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"sujeitar-se a um serviço de widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite que o proprietário utilize a interface de nível superior de um serviço de widget. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir com o administrador de um dispositivo"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistema"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Display sem fio"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectar ao dispositivo"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Transmitir tela para dispositivo"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Procurando dispositivos…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Configurações"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Desconectar"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Verificando..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Conectando..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponível"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição nº <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", seguro"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"O Display sem fio está conectado"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Tela exibida em outro dispositivo."</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Transmitindo a tela"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Conectando a <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Transmitindo a tela"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Conectado a <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Desconectar"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueci o padrão"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 5c56441..6ea1e9e 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -598,6 +598,10 @@
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sa fixar vid in fund davos"</string>
     <!-- no translation found for permdesc_bindWallpaper (7108428692595491668) -->
     <skip />
+    <!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) -->
+    <skip />
+    <!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) -->
+    <skip />
     <!-- no translation found for permlab_bindRemoteViews (5697987759897367099) -->
     <skip />
     <!-- no translation found for permdesc_bindRemoteViews (4717987810137692572) -->
@@ -2411,10 +2415,18 @@
     <skip />
     <!-- no translation found for wireless_display_route_description (9070346425023979651) -->
     <skip />
-    <!-- no translation found for media_route_chooser_grouping_done (7966438307723317169) -->
-    <skip />
     <!-- no translation found for media_route_button_content_description (5758553567065145276) -->
     <skip />
+    <!-- no translation found for media_route_chooser_title (1751618554539087622) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_title_for_remote_display (3395541745872017583) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_searching (4776236202610828706) -->
+    <skip />
+    <!-- no translation found for media_route_chooser_extended_settings (87015534236701604) -->
+    <skip />
+    <!-- no translation found for media_route_controller_disconnect (8966120286374158649) -->
+    <skip />
     <!-- no translation found for media_route_status_scanning (7279908761758293783) -->
     <skip />
     <!-- no translation found for media_route_status_connecting (6422571716007825440) -->
@@ -2435,9 +2447,13 @@
     <skip />
     <!-- no translation found for display_manager_overlay_display_secure_suffix (6022119702628572080) -->
     <skip />
-    <!-- no translation found for wifi_display_notification_title (2223050649240326557) -->
+    <!-- no translation found for wifi_display_notification_connecting_title (2838646471050359706) -->
     <skip />
-    <!-- no translation found for wifi_display_notification_message (4498802012464170685) -->
+    <!-- no translation found for wifi_display_notification_connecting_message (5837350993752841389) -->
+    <skip />
+    <!-- no translation found for wifi_display_notification_connected_title (8567308065912676285) -->
+    <skip />
+    <!-- no translation found for wifi_display_notification_connected_message (2587209325701109715) -->
     <skip />
     <!-- no translation found for wifi_display_notification_disconnect (6183754463561153372) -->
     <skip />
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f29a7e6..c3f9157 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu VPN. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"conectare la o imagine de fundal"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unei imagini de fundal. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"conectare la un ecran la distanță"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Permite proprietarului să se conecteze la interfața de nivel superior a unui ecran la distanță. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"conectare la un serviciu widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Permite proprietarului să se conecteze la interfaţa de nivel superior a unui serviciu widget. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacţionare cu administratorul unui dispozitiv"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Ecran wireless"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Conectați-vă la dispozitiv"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Trimiteți ecranul pe dispozitiv"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Se caută dispozitive..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Setări"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Deconectați-vă"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Se scanează..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Se conectează..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Disponibilă"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Suprapunerea <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", securizat"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Ecranul wireless este conectat"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Acest ecran este afişat pe alt gadget"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Se trimite ecranul"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Se conectează la <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Se trimite ecranul"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Conectat la <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Deconectaţi-vă"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Apel de urgenţă"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 44db6b6..13f18c3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Приложение сможет подключаться к базовому интерфейсу службы VPN. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"Привязка к фоновому рисунку"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Подключение к удаленному дисплею"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Приложение сможет подключаться к базовому интерфейсу службы виджетов. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"Взаимодействие с администратором устройства"</string>
@@ -1348,7 +1350,7 @@
     <string name="submit" msgid="1602335572089911941">"Отправить"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Включен режим \"Штурман\""</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Чтобы выйти, нажмите здесь."</string>
-    <string name="tethered_notification_title" msgid="3146694234398202601">"USB-модем/точка доступа Wi-Fi используется"</string>
+    <string name="tethered_notification_title" msgid="3146694234398202601">"Включен режим модема"</string>
     <string name="tethered_notification_message" msgid="6857031760103062982">"Нажмите для настройки."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Назад"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Далее"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Беспроводной монитор"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Подключение к устройству"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Подключение к удаленному дисплею"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Поиск устройств…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Настройки"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Отключить"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканирование..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Подключение..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Доступен"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наложение № <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> х <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> тчк/дюйм"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безопасный"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Беспроводной проектор подключен"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Изображение передается на другое устройство"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Подключение к удаленному дисплею"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Подключение к <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Удаленный дисплей подключен"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Подключено к <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Отключить"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Экстренный вызов"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забыли графический ключ?"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index a4e57fb..3467b4d 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby VPN. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"väzba na tapetu"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tapety. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"viazať na vzdialený displej"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania vzdialeného displeja. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"viazať sa k službe miniaplikácie"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby miniaplikácií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"komunikovať so správcom zariadenia"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Systém"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Bezdrôtový displej"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Pripojenie k zariadeniu"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Odovzdanie obraz. na prehratie v zariad."</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Prebieha vyhľadávanie zariadení…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavenia"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Odpojiť"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Prebieha vyhľadávanie..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Prebieha pripájanie…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"K dispozícii"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrytie č. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", zabezpečené"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Bezdrôtový displej je pripojený"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Táto obrazovka sa zobrazuje na inom zariadení"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Odovzdávanie obrazovky na prehratie"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Prebieha pripájanie k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Odovzdávanie obrazovky na prehratie"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Pripojené k obrazovke <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Odpojiť"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Tiesňové volanie"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nepamätám si vzor"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c364397..0d76bbf 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Lastniku omogoča povezovanje z vmesnikom storitve navideznega zasebnega omrežja najvišje ravni. Ne uporabljajte za navadne programe."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"povezovanje z ozadjem"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Imetniku omogoča povezavo z vmesnikom ozadja najvišje ravni. Tega nikoli ni treba uporabiti za navadne programe."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"povezava z oddaljenim prikazom"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Imetniku omogoča povezovanje z vmesnikom oddaljenega prikaza najvišje ravni. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"poveži s storitvijo pripomočka"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Lastniku omogoča povezovanje z vmesnikom storitve pripomočka najvišje ravni. Tega ni treba nikoli uporabiti za navadne programe."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcija s skrbnikom naprave"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Brezžični prikaz"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Končano"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Izhod predstavnosti"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Povezovanje z napravo"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Predvajanje zaslona v napravi"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Iskanje naprav …"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Nastavitve"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Prekinitev povezave"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Pregledovanje ..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Vzpostavljanje povezave ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Na voljo"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrivanje #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> pik na palec"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", varen"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Brezžični zaslon je povezan"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Ta zaslon je prikazan v drugi napravi"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Predvajanje zaslona"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Povezovanje z zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Predvajanje zaslona"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Vzpostavljena povezava z zaslonom <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Prekini povezavo"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Klic v sili"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pozabljen vzorec"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 605cde5..6fb9ea2 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозвољава власнику да се повеже са интерфејсом VPN услуге највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"обавезивање на позадину"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"повезивање са удаљеним екраном"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозвољава власнику да се обавеже на интерфејс услуге виџета највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"интеракција са администратором уређаја"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Систем"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Бежични екран"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Повежите са уређајем"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Пребаците екран на уређај"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Тражење уређаја…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Подешавања"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Прекини везу"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Скенирање..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Повезивање..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Доступна"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Постављени елемент бр. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>×<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безбедно"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Бежични екран је повезан"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Овај екран се приказује на другом уређају"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Пребацивање екрана"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Повезивање са <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Пребацивање екрана"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Повезано је са <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Прекини везу"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Хитни позив"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Заборављени шаблон"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 86eaa11..db7d7d0 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en VPN-tjänst. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"binda till en bakgrund"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Innehavaren kan binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bind till en fjärrskärm"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en fjärrskärm. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bind till en widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en widget. Ska inte behövas för vanliga appar."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Trådlös skärm"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klar"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieuppspelning"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Anslut till enhet"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Överför skärmen till enheten"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Söker efter enheter ..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Inställningar"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Koppla från"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Skannar…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Ansluter ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Tillgängliga"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Överlagring #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g> x <xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", säker"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Trådlös anslutning till skärm"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Den här skärmen visas på en annan enhet"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Överför skärmen"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Ansluter till <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Överför skärmen"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Ansluten till <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Koppla från"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Nödsamtal"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glömt ditt grafiska lösenord?"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index aa4b279..30c8092 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Inaruhusu kishikiliaji kushurutisha kusano ya kiwango cha juu cha huduma ya Vpn. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"funga kwa mandhari"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Inaruhusu kishikiliaji kushurutisha kwa kusano ya kiwango cha juu cha mandhari. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"fungisha kwenye mwonekano wa mbali"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Huruhusu mtumiaji kujifungia kiolesura cha kiwango cha juu cha mwonekano wa mbali. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"funga kwenye huduma ya widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Inaruhusu mmiliki kushurutisha kusano ya kiwango cha juu ya huduma ya wijeti. Haipaswi kuhitajika kwa programu za kawaida."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"jiunge na msimamizi wa kifaa"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Mfumo"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Uonyeshaji usiotumia waya"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Nimemaliza"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Unganisha kwenye kifaa"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Tuma skrini kwa kifaa"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Inatafuta vifaa..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Mipangilio"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Ondoa"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Inatambaza..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Inaunganisha..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Inapatikana"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Uwekeleaji #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", salama"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Onyesho pasiwaya limeunganishwa"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Skrini hii inaonyesha kwenye kifaa kingine"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Utumaji wa skrini"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Inaunganishwa kwenye <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Utumaji wa skrini"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Imeungwanishwa kwenye <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Tenganisha"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Simu ya dharura"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Umesahau Ruwaza"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4622005..f298a8f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการ VPN ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"เชื่อมโยงกับวอลเปเปอร์"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ผูกกับจอแสดงผลระยะไกล"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการวิดเจ็ต ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"ติดต่อกับผู้ดูแลอุปกรณ์"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"ระบบ"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"การแสดงผลแบบไร้สาย"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"เชื่อมต่อกับอุปกรณ์"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"ส่งหน้าจอไปยังอุปกรณ์"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"กำลังค้นหาอุปกรณ์…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"การตั้งค่า"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"ยกเลิกการเชื่อมต่อ"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"กำลังสแกน..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"กำลังเชื่อมต่อ..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"พร้อมใช้งาน"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"การวางซ้อน #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", ปลอดภัย"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"เชื่อมต่อการแสดงผลแบบไร้สายอยู่"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"หน้าจอนี้กำลังแสดงบนอุปกรณ์อื่น"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"กำลังส่งหน้าจอ"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"กำลังเชื่อมต่อไปยัง <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"กำลังส่งหน้าจอ"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"เชื่อมต่อกับ <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"หยุดเชื่อมต่อ"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"หมายเลขฉุกเฉิน"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ลืมรูปแบบใช่หรือไม่"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 897a111..85dd968 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng Vpn. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sumailalim sa wallpaper"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng isang wallpaper. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"magpasaklaw sa isang remote na display"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Binibigyang-daan ang may-hawak na masaklaw ang pinakamataas na antas ng interface ng isang remote na display. Hindi dapat kailanman kailanganin ng normal na apps."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"itali sa serbisyo ng widget"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Pinapayagan ang may-hawak na sumailalim sa nangungunang interface ng serbisyo ng widget. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"makipag-ugnay sa tagapangasiwa ng device"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"System"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Wireless display"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Kumonekta sa device"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"I-cast ang screen sa device"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Naghahanap ng mga device…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Mga Setting"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Idiskonekta"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Nagsa-scan..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Kumukonekta..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Available"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", secure"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Nakakonekta ang wireless na display"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Lumalabas ang screen na ito sa isa pang device"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Kina-cast ang screen"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Kumokonekta sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Kina-cast ang screen"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Nakakonekta sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Alisin sa pagkakakonekta"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency na tawag"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nakalimutan ang Pattern"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ffb6ca1..9ca752e 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Cihazın sahibine bir VPN hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"bir duvar kağıdına tabi kıl"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cihazın sahibine, duvar kağıdının en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"uzak ekrana bağlan"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"İzin sahibine, bir uzak ekranın en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bir widget hizmetine bağla"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cihazın sahibine bir widget hizmetinin en üst düzey arayüzüne bağlanma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"bir cihaz yöneticisi ile etkileşimde bulun"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Kablosuz ekran"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Cihaza bağlanın"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Ekranı cihaza yayınlayın"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Cihaz aranıyor…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Ayarlar"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Bağlantıyı kes"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Taranıyor..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Bağlanılıyor..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Kullanılabilir"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Yer Paylaşımı No. <xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", güvenli"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Kablosuz ekrana bağlandı"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Bu ekran başka bir cihazda gösteriliyor"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Ekran yayınlanıyor"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> bağlantısı yapılıyor"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Ekran yayınlanıyor"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> bağlantısı yapıldı"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Bağlantıyı kes"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Acil durum çağrısı"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Deseni Unuttunuz mu?"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f6bc23d..556b35b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби VPN. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"прив’язати до фонового малюнка"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"прив’язуватися до віддаленого екрана"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби віджетів. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"взаємодіяти з адмін. пристрою"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Система"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудіо Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Бездротовий екран"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Вивід медіа-даних"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Під’єднатися до пристрою"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Транслювати екран на пристрій"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Пошук пристроїв…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Налаштування"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Від’єднатися"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Сканування..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"З’єднання..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Доступно"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Накладання №<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>х<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", безпечний"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Бездротовий екран під’єднано"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Цей екран відображається на іншому пристрої"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Транслювання екрана"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"<xliff:g id="NAME">%1$s</xliff:g> – під’єднання"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Транслювання екрана"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"<xliff:g id="NAME">%1$s</xliff:g> – під’єднано"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Від’єднати"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Екстрений виклик"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Не пам’ятаю ключ"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ec68f3a..c8f5014 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ Vpn. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"liên kết với hình nền"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của hình nền. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"liên kết với màn hình từ xa"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của màn hình từ xa. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"liên kết với dịch vụ tiện ích con"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ tiện ích con. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"tương tác với quản trị viên thiết bị"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Hệ thống"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Hiển thị không dây"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Kết nối với thiết bị"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Truyền màn hình tới thiết bị"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Đang tìm kiếm thiết bị…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Cài đặt"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Ngắt kết nối"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Đang quét..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Đang kết nối..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Khả dụng"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Lớp phủ #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", an toàn"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Hiển thị không dây đã được kết nối"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Màn hình này đang hiển thị trên thiết bị khác"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Truyền màn hình"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Đang kết nối với <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Truyền màn hình"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Đã kết nối với <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Ngắt kết nối"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Cuộc gọi khẩn cấp"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Đã quên hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 180accb..ba226af8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允许用户绑定到 VPN 服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"绑定到壁纸"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允许用户绑定到壁纸的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允许应用绑定到小部件服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"与设备管理器交互"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系统"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"无线显示"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"连接到设备"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"将屏幕投射到设备上"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜索设备…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"设置"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"断开连接"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"正在扫描..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"正在连接..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"可连接"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"叠加视图 #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">",安全"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"已连接到无线显示设备"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"此屏幕的内容正显示在另一台设备上"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"正在投射屏幕"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"正在连接到“<xliff:g id="NAME">%1$s</xliff:g>”"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"正在投射屏幕"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"已连接到“<xliff:g id="NAME">%1$s</xliff:g>”"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"断开连接"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"紧急呼救"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘记了图案"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 0fd3fdb..fa0c49b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式繫結至 VPN 服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"繫結至桌布"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (不建議一般應用程式使用)。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音頻"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"連接裝置"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"在裝置上放送螢幕"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"設定"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"停止連接"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"正在掃描…"</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"正在連線..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"可用"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"重疊效果 #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"(安全)"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"已連接無線顯示裝置"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"這個畫面正在另一部裝置上顯示"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"正在放送螢幕"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"正在連線到「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"正在放送螢幕"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"已連線到「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"中斷連線"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖案"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 8f8ccdd..40d6260 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式聯繫至 VPN 服務的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"連結至桌布"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"允許應用程式繫結至小工具服務的頂層介面 (一般應用程式不需使用)。"</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"系統"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"無線螢幕分享"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"連線至裝置"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"將螢幕投放到裝置上"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"正在搜尋裝置..."</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"設定"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"中斷連線"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"掃描中..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"連線中…"</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"可以使用"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"第 <xliff:g id="ID">%1$d</xliff:g> 個重疊效果"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>:<xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>,<xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">"(安全)"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"已連接無線顯示器"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"其他裝置正在顯示這個畫面"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"正在投放螢幕"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"正在連線至「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"正在投放螢幕"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"已連線至「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"中斷連線"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖形"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9f47a5c..563cb3f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -382,6 +382,8 @@
     <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Ivumela umnini ukuthi abophele kwissekelo esingaphezulu sesevisi ye-Vpm. Ayidingakeli izinhlelo zokusebenza ezejwayelekile."</string>
     <string name="permlab_bindWallpaper" msgid="8716400279937856462">"hlanganisa kwiphephadonga"</string>
     <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lwephephadonga. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"bophezela kusibonisi sesilawuli kude"</string>
+    <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Ivumela umbambi ukuhlanganisa isixhumi esibonakalayo esisezingeni eliphezulu sesibonisi sesilawuli kude. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"bophezela kube isevisi yesinqunjana"</string>
     <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Ivumela umbambi ukuhlanganisa uxhumano nomsebenzisi kwezinga eliphezulu lensizakalo yesinqunjwana. Akusoze kwadingeka kwezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"xhumana nomphathi wedivaysi"</string>
@@ -1489,8 +1491,12 @@
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Isistimu"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
     <string name="wireless_display_route_description" msgid="9070346425023979651">"Ukubonisa okungenazintambo"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Qedile"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string>
+    <string name="media_route_chooser_title" msgid="1751618554539087622">"Xhuma kudivayisi"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Lingisa isikrini kudivayisi"</string>
+    <string name="media_route_chooser_searching" msgid="4776236202610828706">"Isesha amadivayisi…"</string>
+    <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Izilungiselelo"</string>
+    <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Nqamula"</string>
     <string name="media_route_status_scanning" msgid="7279908761758293783">"Iyaskena..."</string>
     <string name="media_route_status_connecting" msgid="6422571716007825440">"Iyaxhuma..."</string>
     <string name="media_route_status_available" msgid="6983258067194649391">"Kuyatholakala"</string>
@@ -1501,8 +1507,10 @@
     <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Isendlalelo #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", kuphephile"</string>
-    <string name="wifi_display_notification_title" msgid="2223050649240326557">"Ukubukeka okungenantambo kuxhunyiwe"</string>
-    <string name="wifi_display_notification_message" msgid="4498802012464170685">"Lesi sikrini siyabonakala kwenye idivayisi"</string>
+    <string name="wifi_display_notification_connecting_title" msgid="2838646471050359706">"Isikrini sokulingisa"</string>
+    <string name="wifi_display_notification_connecting_message" msgid="5837350993752841389">"Ixhuma ku-<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="wifi_display_notification_connected_title" msgid="8567308065912676285">"Isikrini sokulingisa"</string>
+    <string name="wifi_display_notification_connected_message" msgid="2587209325701109715">"Kuxhunywe ku-<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="wifi_display_notification_disconnect" msgid="6183754463561153372">"Nqamula"</string>
     <string name="kg_emergency_call_label" msgid="684946192523830531">"Ucingo lwezimo eziphuthumayo"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ukhohlwe iphethini?"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 18cf57d..b34c792 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1189,6 +1189,9 @@
         <item>12</item> <!-- EVDO_B -->
     </integer-array>
 
+    <!-- Set to true if after a provisioning apn the radio should be restarted -->
+    <bool name="config_restartRadioAfterProvisioning">false</bool>
+
     <!-- Vibrator pattern to be used as the default for notifications
          that specify DEFAULT_VIBRATE.
      -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 62f26c6..9025400a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1052,6 +1052,12 @@
         interface of a wallpaper. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindRemoteDisplay">bind to a remote display</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
+        interface of a remote display. Should never be needed for normal apps.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindRemoteViews">bind to a widget service</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindRemoteViews">Allows the holder to bind to the top-level
@@ -4090,12 +4096,24 @@
     <!-- Description of a wireless display route. [CHAR LIMIT=50] -->
     <string name="wireless_display_route_description">Wireless display</string>
 
-    <!-- "Done" button for MediaRouter chooser dialog when grouping routes. [CHAR LIMIT=NONE] -->
-    <string name="media_route_chooser_grouping_done">Done</string>
-
     <!-- Content description of a MediaRouteButton for accessibility support -->
     <string name="media_route_button_content_description">Media output</string>
 
+    <!-- Title of the media route chooser dialog. [CHAR LIMIT=40] -->
+    <string name="media_route_chooser_title">Connect to device</string>
+
+    <!-- Title of the media route chooser dialog for selecting remote display routes. [CHAR LIMIT=40] -->
+    <string name="media_route_chooser_title_for_remote_display">Cast screen to device</string>
+
+    <!-- Placeholder text to show when no devices have been found. [CHAR LIMIT=50] -->
+    <string name="media_route_chooser_searching">Searching for devices\u2026</string>
+
+    <!-- Button to access extended settings.  [CHAR LIMIT=30] -->
+    <string name="media_route_chooser_extended_settings">Settings</string>
+
+    <!-- Button to disconnect from a media route.  [CHAR LIMIT=30] -->
+    <string name="media_route_controller_disconnect">Disconnect</string>
+
     <!-- Status message for remote routes attempting to scan/determine availability -->
     <string name="media_route_status_scanning">Scanning...</string>
 
@@ -4128,10 +4146,14 @@
     <!-- Title text to append when the display is secure.  [CHAR LIMIT=30] -->
     <string name="display_manager_overlay_display_secure_suffix">, secure</string>
 
+    <!-- Title of the notification to indicate the process of connecting to a wifi display.  [CHAR LIMIT=50] -->
+    <string name="wifi_display_notification_connecting_title">Casting screen</string>
+    <!-- Message of the notification to indicate the process of connecting to a wifi display.  [CHAR LIMIT=80] -->
+    <string name="wifi_display_notification_connecting_message">Connecting to <xliff:g id="name">%1$s</xliff:g></string>
     <!-- Title of the notification to indicate an active wifi display connection.  [CHAR LIMIT=50] -->
-    <string name="wifi_display_notification_title">Wireless display is connected</string>
+    <string name="wifi_display_notification_connected_title">Casting screen</string>
     <!-- Message of the notification to indicate an active wifi display connection.  [CHAR LIMIT=80] -->
-    <string name="wifi_display_notification_message">This screen is showing on another device</string>
+    <string name="wifi_display_notification_connected_message">Connected to <xliff:g id="name">%1$s</xliff:g></string>
     <!-- Label of a button to disconnect an active wifi display connection.  [CHAR LIMIT=25] -->
     <string name="wifi_display_notification_disconnect">Disconnect</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b85bff4..6d90973 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -283,6 +283,7 @@
   <java-symbol type="bool" name="config_safe_media_volume_enabled" />
   <java-symbol type="bool" name="config_camera_sound_forced" />
   <java-symbol type="bool" name="config_dontPreferApn" />
+  <java-symbol type="bool" name="config_restartRadioAfterProvisioning" />
   <java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
   <java-symbol type="bool" name="config_useFixedVolume" />
   <java-symbol type="bool" name="config_forceDefaultOrientation" />
@@ -1096,7 +1097,11 @@
   <java-symbol type="drawable" name="notification_template_icon_bg" />
   <java-symbol type="drawable" name="notification_template_icon_low_bg" />
   <java-symbol type="drawable" name="ic_media_route_on_holo_dark" />
+  <java-symbol type="drawable" name="ic_media_route_off_holo_dark" />
+  <java-symbol type="drawable" name="ic_media_route_connecting_holo_dark" />
   <java-symbol type="drawable" name="ic_media_route_disabled_holo_dark" />
+  <java-symbol type="drawable" name="ic_notification_cast_connecting" />
+  <java-symbol type="drawable" name="ic_notification_cast_on" />
   <java-symbol type="drawable" name="cling_button" />
   <java-symbol type="drawable" name="cling_arrow_up" />
   <java-symbol type="drawable" name="cling_bg" />
@@ -1253,17 +1258,17 @@
 
   <java-symbol type="attr" name="mediaRouteButtonStyle" />
   <java-symbol type="attr" name="externalRouteEnabledDrawable" />
-  <java-symbol type="id" name="extended_settings" />
-  <java-symbol type="id" name="check" />
-  <java-symbol type="id" name="volume_slider" />
-  <java-symbol type="id" name="volume_icon" />
-  <java-symbol type="drawable" name="ic_media_route_on_holo_dark" />
-  <java-symbol type="layout" name="media_route_chooser_layout" />
-  <java-symbol type="layout" name="media_route_list_item_top_header" />
-  <java-symbol type="layout" name="media_route_list_item_section_header" />
+  <java-symbol type="layout" name="media_route_chooser_dialog" />
+  <java-symbol type="layout" name="media_route_controller_dialog" />
   <java-symbol type="layout" name="media_route_list_item" />
-  <java-symbol type="layout" name="media_route_list_item_checkable" />
-  <java-symbol type="layout" name="media_route_list_item_collapse_group" />
+  <java-symbol type="id" name="media_route_list" />
+  <java-symbol type="id" name="media_route_volume_layout" />
+  <java-symbol type="id" name="media_route_volume_slider" />
+  <java-symbol type="id" name="media_route_control_frame" />
+  <java-symbol type="id" name="media_route_disconnect_button" />
+  <java-symbol type="id" name="media_route_extended_settings_button" />
+  <java-symbol type="string" name="media_route_chooser_title" />
+  <java-symbol type="string" name="media_route_chooser_title_for_remote_display" />
   <java-symbol type="string" name="bluetooth_a2dp_audio_route_name" />
 
   <java-symbol type="dimen" name="config_minScalingSpan" />
@@ -1451,7 +1456,6 @@
   <java-symbol type="color" name="config_defaultNotificationColor" />
   <java-symbol type="color" name="input_method_navigation_guard" />
   <java-symbol type="drawable" name="ic_notification_ime_default" />
-  <java-symbol type="drawable" name="ic_notify_wifidisplay" />
   <java-symbol type="drawable" name="ic_menu_refresh" />
   <java-symbol type="drawable" name="stat_notify_car_mode" />
   <java-symbol type="drawable" name="stat_notify_disabled" />
@@ -1594,8 +1598,10 @@
   <java-symbol type="string" name="vpn_lockdown_error" />
   <java-symbol type="string" name="vpn_lockdown_config" />
   <java-symbol type="string" name="wallpaper_binding_label" />
-  <java-symbol type="string" name="wifi_display_notification_title" />
-  <java-symbol type="string" name="wifi_display_notification_message" />
+  <java-symbol type="string" name="wifi_display_notification_connecting_title" />
+  <java-symbol type="string" name="wifi_display_notification_connecting_message" />
+  <java-symbol type="string" name="wifi_display_notification_connected_title" />
+  <java-symbol type="string" name="wifi_display_notification_connected_message" />
   <java-symbol type="string" name="wifi_display_notification_disconnect" />
   <java-symbol type="style" name="Theme.Dialog.AppError" />
   <java-symbol type="style" name="Theme.Toast" />
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 7af3b9c..3215e17 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -58,4 +58,12 @@
   </array>
   <!-- This is the battery capacity in mAh (measured at nominal voltage) -->
   <item name="battery.capacity">1000</item>
+
+  <array name="wifi.batchedscan"> <!-- mA -->
+      <value>.0002</value> <!-- 1-8/hr -->
+      <value>.002</value>  <!-- 9-64/hr -->
+      <value>.02</value>   <!-- 65-512/hr -->
+      <value>.2</value>    <!-- 513-4,096/hr -->
+      <value>2</value>    <!-- 4097-/hr -->
+  </array>
 </device>
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 76b702e..4a58f88 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -36,8 +36,6 @@
 import com.android.bandwidthtest.util.ConnectionUtil;
 
 import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * Test that downloads files from a test server and reports the bandwidth metrics collected.
@@ -131,8 +129,8 @@
         results.putString("device_id", mDeviceId);
         results.putString("timestamp", ts);
         results.putInt("size", FILE_SIZE);
-        AddStatsToResults(PROF_LABEL, prof_stats, results);
-        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+        addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
         getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
 
         // Clean up.
@@ -185,8 +183,8 @@
         results.putString("device_id", mDeviceId);
         results.putString("timestamp", ts);
         results.putInt("size", FILE_SIZE);
-        AddStatsToResults(PROF_LABEL, prof_stats, results);
-        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+        addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
         getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
 
         // Clean up.
@@ -242,8 +240,9 @@
         results.putString("device_id", mDeviceId);
         results.putString("timestamp", ts);
         results.putInt("size", FILE_SIZE);
-        AddStatsToResults(PROF_LABEL, prof_stats, results);
-        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+        // remember to use download manager uid for proc stats
+        addStatsToResults(PROC_LABEL, proc_stats, results, downloadManagerUid);
         getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
 
         // Clean up.
@@ -302,46 +301,35 @@
      * @param label to attach to this given stats.
      * @param stats {@link NetworkStats} to add.
      * @param results {@link Bundle} to be added to.
+     * @param uid for which to report the results.
      */
-    public void AddStatsToResults(String label, NetworkStats stats, Bundle results){
+    public void addStatsToResults(String label, NetworkStats stats, Bundle results, int uid){
         if (results == null || results.isEmpty()) {
             Log.e(LOG_TAG, "Empty bundle provided.");
             return;
         }
-        // Merge stats across all sets.
-        Map<Integer, Entry> totalStats = new HashMap<Integer, Entry>();
+        Entry totalStats = null;
         for (int i = 0; i < stats.size(); ++i) {
             Entry statsEntry = stats.getValues(i, null);
             // We are only interested in the all inclusive stats.
             if (statsEntry.tag != 0) {
                 continue;
             }
-            Entry mapEntry = null;
-            if (totalStats.containsKey(statsEntry.uid)) {
-                mapEntry = totalStats.get(statsEntry.uid);
-                switch (statsEntry.set) {
-                    case NetworkStats.SET_ALL:
-                        mapEntry.rxBytes = statsEntry.rxBytes;
-                        mapEntry.txBytes = statsEntry.txBytes;
-                        break;
-                    case NetworkStats.SET_DEFAULT:
-                    case NetworkStats.SET_FOREGROUND:
-                        mapEntry.rxBytes += statsEntry.rxBytes;
-                        mapEntry.txBytes += statsEntry.txBytes;
-                        break;
-                    default:
-                        Log.w(LOG_TAG, "Invalid state found in NetworkStats.");
-                }
+            // skip stats for other uids
+            if (statsEntry.uid != uid) {
+                continue;
+            }
+            if (totalStats == null || statsEntry.set == NetworkStats.SET_ALL) {
+                totalStats = statsEntry;
             } else {
-                totalStats.put(statsEntry.uid, statsEntry);
+                totalStats.rxBytes += statsEntry.rxBytes;
+                totalStats.txBytes += statsEntry.txBytes;
             }
         }
-        // Ouput merged stats to bundle.
-        for (Entry entry : totalStats.values()) {
-            results.putInt(label + "uid", entry.uid);
-            results.putLong(label + "tx", entry.txBytes);
-            results.putLong(label + "rx", entry.rxBytes);
-        }
+        // Output merged stats to bundle.
+        results.putInt(label + "uid", totalStats.uid);
+        results.putLong(label + "tx", totalStats.txBytes);
+        results.putLong(label + "rx", totalStats.rxBytes);
     }
 
     /**
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index 783e1f8..ae4bc88 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -17,19 +17,19 @@
         $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
         $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
 	$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
 	$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
 	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index b30be56..3c09297 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -17,19 +17,19 @@
 	$(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
 	$(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
 	$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
 	$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
 	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk
index 49b6154..0f4b8ad 100644
--- a/data/sounds/AudioPackage8.mk
+++ b/data/sounds/AudioPackage8.mk
@@ -17,11 +17,11 @@
 	$(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
 	$(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
 	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk
index 87b7764..36dc921 100644
--- a/data/sounds/AudioPackage9.mk
+++ b/data/sounds/AudioPackage9.mk
@@ -17,11 +17,11 @@
         $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
         $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
 	$(LOCAL_PATH)/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
diff --git a/data/sounds/notifications/ogg/Tethys_48k.ogg b/data/sounds/notifications/ogg/Tethys_48k.ogg
index a9d8bbd..355d522 100644
--- a/data/sounds/notifications/ogg/Tethys_48k.ogg
+++ b/data/sounds/notifications/ogg/Tethys_48k.ogg
Binary files differ
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index af8441a..aac7876 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -88,9 +88,10 @@
     @Override
     public boolean getPadding(Rect padding) {
         final Rect r = mDrawableContainerState.getConstantPadding();
-        boolean result = true;
+        boolean result;
         if (r != null) {
             padding.set(r);
+            result = (r.left | r.top | r.bottom | r.right) != 0;
         } else {
             if (mCurrDrawable != null) {
                 result = mCurrDrawable.getPadding(padding);
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index ab34c0f..9c57a2c 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -244,7 +244,7 @@
         } else {
             padding.set(mPadding);
         }
-        return true;
+        return (padding.left | padding.top | padding.right | padding.bottom) != 0;
     }
 
     /**
diff --git a/media/java/android/media/IMediaRouterClient.aidl b/media/java/android/media/IMediaRouterClient.aidl
new file mode 100644
index 0000000..9640dcb
--- /dev/null
+++ b/media/java/android/media/IMediaRouterClient.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 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;
+
+/**
+ * {@hide}
+ */
+oneway interface IMediaRouterClient {
+    void onStateChanged();
+}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
new file mode 100644
index 0000000..f8f5fdf
--- /dev/null
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 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;
+
+import android.media.IMediaRouterClient;
+import android.media.MediaRouterClientState;
+
+/**
+ * {@hide}
+ */
+interface IMediaRouterService {
+    void registerClientAsUser(IMediaRouterClient client, String packageName, int userId);
+    void unregisterClient(IMediaRouterClient client);
+
+    MediaRouterClientState getState(IMediaRouterClient client);
+
+    void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
+    void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
+    void requestSetVolume(IMediaRouterClient client, String routeId, int volume);
+    void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction);
+}
diff --git a/media/java/android/media/IRemoteDisplayCallback.aidl b/media/java/android/media/IRemoteDisplayCallback.aidl
new file mode 100644
index 0000000..19cf070
--- /dev/null
+++ b/media/java/android/media/IRemoteDisplayCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 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;
+
+import android.media.RemoteDisplayState;
+
+/**
+ * {@hide}
+ */
+oneway interface IRemoteDisplayCallback {
+    void onStateChanged(in RemoteDisplayState state);
+}
diff --git a/media/java/android/media/IRemoteDisplayProvider.aidl b/media/java/android/media/IRemoteDisplayProvider.aidl
new file mode 100644
index 0000000..b0d7379
--- /dev/null
+++ b/media/java/android/media/IRemoteDisplayProvider.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 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;
+
+import android.media.IRemoteDisplayCallback;
+
+/**
+ * {@hide}
+ */
+oneway interface IRemoteDisplayProvider {
+    void setCallback(in IRemoteDisplayCallback callback);
+    void setDiscoveryMode(int mode);
+    void connect(String id);
+    void disconnect(String id);
+    void setVolume(String id, int volume);
+    void adjustVolume(String id, int delta);
+}
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 59d411d..34008bb 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -1930,7 +1930,6 @@
         int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
         synchronized(mAudioFocusLock) {
             synchronized(mRCStack) {
-                boolean wasCurrentRcController = isCurrentRcController(mediaIntent);
                 // store the new display information
                 try {
                     for (int index = mRCStack.size()-1; index >= 0; index--) {
@@ -1977,9 +1976,9 @@
                     Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
                 }
 
-                // if the eventReceiver is now at the top of the stack but wasn't before
+                // if the eventReceiver is at the top of the stack
                 // then check for potential refresh of the remote controls
-                if (isCurrentRcController(mediaIntent) && !wasCurrentRcController) {
+                if (isCurrentRcController(mediaIntent)) {
                     checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
                 }
             }//synchronized(mRCStack)
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 9a79c94..525dc4f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -16,11 +16,15 @@
 
 package android.media;
 
+import com.android.internal.util.Objects;
+
+import android.Manifest;
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
@@ -28,8 +32,10 @@
 import android.hardware.display.WifiDisplayStatus;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
@@ -52,14 +58,17 @@
  */
 public class MediaRouter {
     private static final String TAG = "MediaRouter";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     static class Static implements DisplayManager.DisplayListener {
         // Time between wifi display scans when actively scanning in milliseconds.
-        private static final int WIFI_DISPLAY_SCAN_INTERVAL = 15000;
+        private static final int WIFI_DISPLAY_SCAN_INTERVAL = 10000;
 
+        final Context mAppContext;
         final Resources mResources;
         final IAudioService mAudioService;
         final DisplayManager mDisplayService;
+        final IMediaRouterService mMediaRouterService;
         final Handler mHandler;
         final CopyOnWriteArrayList<CallbackInfo> mCallbacks =
                 new CopyOnWriteArrayList<CallbackInfo>();
@@ -76,9 +85,16 @@
 
         RouteInfo mSelectedRoute;
 
-        WifiDisplayStatus mLastKnownWifiDisplayStatus;
+        final boolean mCanConfigureWifiDisplays;
         boolean mActivelyScanningWifiDisplays;
 
+        int mDiscoveryRequestRouteTypes;
+        boolean mDiscoverRequestActiveScan;
+
+        int mCurrentUserId = -1;
+        IMediaRouterClient mClient;
+        MediaRouterClientState mClientState;
+
         final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() {
             @Override
             public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
@@ -101,6 +117,7 @@
         };
 
         Static(Context appContext) {
+            mAppContext = appContext;
             mResources = Resources.getSystem();
             mHandler = new Handler(appContext.getMainLooper());
 
@@ -109,10 +126,20 @@
 
             mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE);
 
+            mMediaRouterService = IMediaRouterService.Stub.asInterface(
+                    ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
+
             mSystemCategory = new RouteCategory(
                     com.android.internal.R.string.default_audio_route_category_name,
                     ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false);
             mSystemCategory.mIsSystem = true;
+
+            // Only the system can configure wifi displays.  The display manager
+            // enforces this with a permission check.  Set a flag here so that we
+            // know whether this process is actually allowed to scan and connect.
+            mCanConfigureWifiDisplays = appContext.checkPermission(
+                    Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED;
         }
 
         // Called after sStatic is initialized
@@ -120,8 +147,7 @@
             mDefaultAudioVideo = new RouteInfo(mSystemCategory);
             mDefaultAudioVideo.mNameResId = com.android.internal.R.string.default_audio_route_name;
             mDefaultAudioVideo.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
-            mDefaultAudioVideo.mPresentationDisplay = choosePresentationDisplayForRoute(
-                    mDefaultAudioVideo, getAllPresentationDisplays());
+            mDefaultAudioVideo.updatePresentationDisplay();
             addRouteStatic(mDefaultAudioVideo);
 
             // This will select the active wifi display route if there is one.
@@ -146,10 +172,13 @@
                 updateAudioRoutes(newAudioRoutes);
             }
 
+            // Bind to the media router service.
+            rebindAsUser(UserHandle.myUserId());
+
             // Select the default route if the above didn't sync us up
             // appropriately with relevant system state.
             if (mSelectedRoute == null) {
-                selectRouteStatic(mDefaultAudioVideo.getSupportedTypes(), mDefaultAudioVideo);
+                selectDefaultRouteStatic();
             }
         }
 
@@ -197,7 +226,7 @@
                         dispatchRouteChanged(sStatic.mBluetoothA2dpRoute);
                     }
                 } else if (sStatic.mBluetoothA2dpRoute != null) {
-                    removeRoute(sStatic.mBluetoothA2dpRoute);
+                    removeRouteStatic(sStatic.mBluetoothA2dpRoute);
                     sStatic.mBluetoothA2dpRoute = null;
                 }
             }
@@ -205,16 +234,52 @@
             if (mBluetoothA2dpRoute != null) {
                 if (mainType != AudioRoutesInfo.MAIN_SPEAKER &&
                         mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo);
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
                 } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
                         a2dpEnabled) {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute);
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false);
                 }
             }
         }
 
-        void updateActiveScan() {
-            if (hasActiveScanCallbackOfType(ROUTE_TYPE_LIVE_VIDEO)) {
+        void updateDiscoveryRequest() {
+            // What are we looking for today?
+            int routeTypes = 0;
+            int passiveRouteTypes = 0;
+            boolean activeScan = false;
+            boolean activeScanWifiDisplay = false;
+            final int count = mCallbacks.size();
+            for (int i = 0; i < count; i++) {
+                CallbackInfo cbi = mCallbacks.get(i);
+                if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN
+                        | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) {
+                    // Discovery explicitly requested.
+                    routeTypes |= cbi.type;
+                } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) {
+                    // Discovery only passively requested.
+                    passiveRouteTypes |= cbi.type;
+                } else {
+                    // Legacy case since applications don't specify the discovery flag.
+                    // Unfortunately we just have to assume they always need discovery
+                    // whenever they have a callback registered.
+                    routeTypes |= cbi.type;
+                }
+                if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
+                    activeScan = true;
+                    if ((cbi.type & ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+                        activeScanWifiDisplay = true;
+                    }
+                }
+            }
+            if (routeTypes != 0 || activeScan) {
+                // If someone else requests discovery then enable the passive listeners.
+                // This is used by the MediaRouteButton and MediaRouteActionProvider since
+                // they don't receive lifecycle callbacks from the Activity.
+                routeTypes |= passiveRouteTypes;
+            }
+
+            // Update wifi display scanning.
+            if (activeScanWifiDisplay && mCanConfigureWifiDisplays) {
                 if (!mActivelyScanningWifiDisplays) {
                     mActivelyScanningWifiDisplays = true;
                     mHandler.post(mScanWifiDisplays);
@@ -225,18 +290,14 @@
                     mHandler.removeCallbacks(mScanWifiDisplays);
                 }
             }
-        }
 
-        private boolean hasActiveScanCallbackOfType(int type) {
-            final int count = mCallbacks.size();
-            for (int i = 0; i < count; i++) {
-                CallbackInfo cbi = mCallbacks.get(i);
-                if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0
-                        && (cbi.type & type) != 0) {
-                    return true;
-                }
+            // Tell the media router service all about it.
+            if (routeTypes != mDiscoveryRequestRouteTypes
+                    || activeScan != mDiscoverRequestActiveScan) {
+                mDiscoveryRequestRouteTypes = routeTypes;
+                mDiscoverRequestActiveScan = activeScan;
+                publishClientDiscoveryRequest();
             }
-            return false;
         }
 
         @Override
@@ -259,18 +320,268 @@
         }
 
         private void updatePresentationDisplays(int changedDisplayId) {
-            final Display[] displays = getAllPresentationDisplays();
             final int count = mRoutes.size();
             for (int i = 0; i < count; i++) {
-                final RouteInfo info = mRoutes.get(i);
-                Display display = choosePresentationDisplayForRoute(info, displays);
-                if (display != info.mPresentationDisplay
-                        || (display != null && display.getDisplayId() == changedDisplayId)) {
-                    info.mPresentationDisplay = display;
-                    dispatchRoutePresentationDisplayChanged(info);
+                final RouteInfo route = mRoutes.get(i);
+                if (route.updatePresentationDisplay() || (route.mPresentationDisplay != null
+                        && route.mPresentationDisplay.getDisplayId() == changedDisplayId)) {
+                    dispatchRoutePresentationDisplayChanged(route);
                 }
             }
         }
+
+        void setSelectedRoute(RouteInfo info, boolean explicit) {
+            // Must be non-reentrant.
+            mSelectedRoute = info;
+            publishClientSelectedRoute(explicit);
+        }
+
+        void rebindAsUser(int userId) {
+            if (mCurrentUserId != userId || userId < 0 || mClient == null) {
+                if (mClient != null) {
+                    try {
+                        mMediaRouterService.unregisterClient(mClient);
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Unable to unregister media router client.", ex);
+                    }
+                    mClient = null;
+                }
+
+                mCurrentUserId = userId;
+
+                try {
+                    Client client = new Client();
+                    mMediaRouterService.registerClientAsUser(client,
+                            mAppContext.getPackageName(), userId);
+                    mClient = client;
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to register media router client.", ex);
+                }
+
+                publishClientDiscoveryRequest();
+                publishClientSelectedRoute(false);
+                updateClientState();
+            }
+        }
+
+        void publishClientDiscoveryRequest() {
+            if (mClient != null) {
+                try {
+                    mMediaRouterService.setDiscoveryRequest(mClient,
+                            mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to publish media router client discovery request.", ex);
+                }
+            }
+        }
+
+        void publishClientSelectedRoute(boolean explicit) {
+            if (mClient != null) {
+                try {
+                    mMediaRouterService.setSelectedRoute(mClient,
+                            mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null,
+                            explicit);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to publish media router client selected route.", ex);
+                }
+            }
+        }
+
+        void updateClientState() {
+            // Update the client state.
+            mClientState = null;
+            if (mClient != null) {
+                try {
+                    mClientState = mMediaRouterService.getState(mClient);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to retrieve media router client state.", ex);
+                }
+            }
+            final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes =
+                    mClientState != null ? mClientState.routes : null;
+            final String globallySelectedRouteId = mClientState != null ?
+                    mClientState.globallySelectedRouteId : null;
+
+            // Add or update routes.
+            final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0;
+            for (int i = 0; i < globalRouteCount; i++) {
+                final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i);
+                RouteInfo route = findGlobalRoute(globalRoute.id);
+                if (route == null) {
+                    route = makeGlobalRoute(globalRoute);
+                    addRouteStatic(route);
+                } else {
+                    updateGlobalRoute(route, globalRoute);
+                }
+            }
+
+            // Synchronize state with the globally selected route.
+            if (globallySelectedRouteId != null) {
+                final RouteInfo route = findGlobalRoute(globallySelectedRouteId);
+                if (route == null) {
+                    Log.w(TAG, "Could not find new globally selected route: "
+                            + globallySelectedRouteId);
+                } else if (route != mSelectedRoute) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Selecting new globally selected route: " + route);
+                    }
+                    selectRouteStatic(route.mSupportedTypes, route, false);
+                }
+            } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute);
+                }
+                selectDefaultRouteStatic();
+            }
+
+            // Remove defunct routes.
+            outer: for (int i = mRoutes.size(); i-- > 0; ) {
+                final RouteInfo route = mRoutes.get(i);
+                final String globalRouteId = route.mGlobalRouteId;
+                if (globalRouteId != null) {
+                    for (int j = 0; j < globalRouteCount; j++) {
+                        MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j);
+                        if (globalRouteId.equals(globalRoute.id)) {
+                            continue outer; // found
+                        }
+                    }
+                    // not found
+                    removeRouteStatic(route);
+                }
+            }
+        }
+
+        void requestSetVolume(RouteInfo route, int volume) {
+            if (route.mGlobalRouteId != null && mClient != null) {
+                try {
+                    mMediaRouterService.requestSetVolume(mClient,
+                            route.mGlobalRouteId, volume);
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "Unable to request volume change.", ex);
+                }
+            }
+        }
+
+        void requestUpdateVolume(RouteInfo route, int direction) {
+            if (route.mGlobalRouteId != null && mClient != null) {
+                try {
+                    mMediaRouterService.requestUpdateVolume(mClient,
+                            route.mGlobalRouteId, direction);
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "Unable to request volume change.", ex);
+                }
+            }
+        }
+
+        RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) {
+            RouteInfo route = new RouteInfo(sStatic.mSystemCategory);
+            route.mGlobalRouteId = globalRoute.id;
+            route.mName = globalRoute.name;
+            route.mDescription = globalRoute.description;
+            route.mSupportedTypes = globalRoute.supportedTypes;
+            route.mEnabled = globalRoute.enabled;
+            route.setRealStatusCode(globalRoute.statusCode);
+            route.mPlaybackType = globalRoute.playbackType;
+            route.mPlaybackStream = globalRoute.playbackStream;
+            route.mVolume = globalRoute.volume;
+            route.mVolumeMax = globalRoute.volumeMax;
+            route.mVolumeHandling = globalRoute.volumeHandling;
+            route.mPresentationDisplayId = globalRoute.presentationDisplayId;
+            route.updatePresentationDisplay();
+            return route;
+        }
+
+        void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) {
+            boolean changed = false;
+            boolean volumeChanged = false;
+            boolean presentationDisplayChanged = false;
+
+            if (!Objects.equal(route.mName, globalRoute.name)) {
+                route.mName = globalRoute.name;
+                changed = true;
+            }
+            if (!Objects.equal(route.mDescription, globalRoute.description)) {
+                route.mDescription = globalRoute.description;
+                changed = true;
+            }
+            final int oldSupportedTypes = route.mSupportedTypes;
+            if (oldSupportedTypes != globalRoute.supportedTypes) {
+                route.mSupportedTypes = globalRoute.supportedTypes;
+                changed = true;
+            }
+            if (route.mEnabled != globalRoute.enabled) {
+                route.mEnabled = globalRoute.enabled;
+                changed = true;
+            }
+            if (route.mRealStatusCode != globalRoute.statusCode) {
+                route.setRealStatusCode(globalRoute.statusCode);
+                changed = true;
+            }
+            if (route.mPlaybackType != globalRoute.playbackType) {
+                route.mPlaybackType = globalRoute.playbackType;
+                changed = true;
+            }
+            if (route.mPlaybackStream != globalRoute.playbackStream) {
+                route.mPlaybackStream = globalRoute.playbackStream;
+                changed = true;
+            }
+            if (route.mVolume != globalRoute.volume) {
+                route.mVolume = globalRoute.volume;
+                changed = true;
+                volumeChanged = true;
+            }
+            if (route.mVolumeMax != globalRoute.volumeMax) {
+                route.mVolumeMax = globalRoute.volumeMax;
+                changed = true;
+                volumeChanged = true;
+            }
+            if (route.mVolumeHandling != globalRoute.volumeHandling) {
+                route.mVolumeHandling = globalRoute.volumeHandling;
+                changed = true;
+                volumeChanged = true;
+            }
+            if (route.mPresentationDisplayId != globalRoute.presentationDisplayId) {
+                route.mPresentationDisplayId = globalRoute.presentationDisplayId;
+                route.updatePresentationDisplay();
+                changed = true;
+                presentationDisplayChanged = true;
+            }
+
+            if (changed) {
+                dispatchRouteChanged(route, oldSupportedTypes);
+            }
+            if (volumeChanged) {
+                dispatchRouteVolumeChanged(route);
+            }
+            if (presentationDisplayChanged) {
+                dispatchRoutePresentationDisplayChanged(route);
+            }
+        }
+
+        RouteInfo findGlobalRoute(String globalRouteId) {
+            final int count = mRoutes.size();
+            for (int i = 0; i < count; i++) {
+                final RouteInfo route = mRoutes.get(i);
+                if (globalRouteId.equals(route.mGlobalRouteId)) {
+                    return route;
+                }
+            }
+            return null;
+        }
+
+        final class Client extends IMediaRouterClient.Stub {
+            @Override
+            public void onStateChanged() {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (Client.this == mClient) {
+                            updateClientState();
+                        }
+                    }
+                });
+            }
+        }
     }
 
     static Static sStatic;
@@ -285,7 +596,7 @@
      * <p>Once initiated this routing is transparent to the application. All audio
      * played on the media stream will be routed to the selected destination.</p>
      */
-    public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1;
+    public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0;
 
     /**
      * Route type flag for live video.
@@ -302,7 +613,13 @@
      * @see RouteInfo#getPresentationDisplay()
      * @see android.app.Presentation
      */
-    public static final int ROUTE_TYPE_LIVE_VIDEO = 0x2;
+    public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1;
+
+    /**
+     * Temporary interop constant to identify remote displays.
+     * @hide To be removed when media router API is updated.
+     */
+    public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2;
 
     /**
      * Route type flag for application-specific usage.
@@ -312,7 +629,10 @@
      * is expected to interpret the meaning of these events and perform the requested
      * routing tasks.</p>
      */
-    public static final int ROUTE_TYPE_USER = 0x00800000;
+    public static final int ROUTE_TYPE_USER = 1 << 23;
+
+    static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO
+            | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER;
 
     /**
      * Flag for {@link #addCallback}: Actively scan for routes while this callback
@@ -336,11 +656,40 @@
      * Flag for {@link #addCallback}: Do not filter route events.
      * <p>
      * When this flag is specified, the callback will be invoked for event that affect any
-     * route event if they do not match the callback's associated media route selector.
+     * route even if they do not match the callback's filter.
      * </p>
      */
     public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1;
 
+    /**
+     * Explicitly requests discovery.
+     *
+     * @hide Future API ported from support library.  Revisit this later.
+     */
+    public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2;
+
+    /**
+     * Requests that discovery be performed but only if there is some other active
+     * callback already registered.
+     *
+     * @hide Compatibility workaround for the fact that applications do not currently
+     * request discovery explicitly (except when using the support library API).
+     */
+    public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3;
+
+    /**
+     * Flag for {@link #isRouteAvailable}: Ignore the default route.
+     * <p>
+     * This flag is used to determine whether a matching non-default route is available.
+     * This constraint may be used to decide whether to offer the route chooser dialog
+     * to the user.  There is no point offering the chooser if there are no
+     * non-default choices.
+     * </p>
+     *
+     * @hide Future API ported from support library.  Revisit this later.
+     */
+    public static final int AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE = 1 << 0;
+
     // Maps application contexts
     static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>();
 
@@ -352,6 +701,9 @@
         if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) {
             result.append("ROUTE_TYPE_LIVE_VIDEO ");
         }
+        if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+            result.append("ROUTE_TYPE_REMOTE_DISPLAY ");
+        }
         if ((types & ROUTE_TYPE_USER) != 0) {
             result.append("ROUTE_TYPE_USER ");
         }
@@ -388,6 +740,11 @@
         return sStatic.mSystemCategory;
     }
 
+    /** @hide */
+    public RouteInfo getSelectedRoute() {
+        return getSelectedRoute(ROUTE_TYPE_ANY);
+    }
+
     /**
      * Return the currently selected route for any of the given types
      *
@@ -411,6 +768,38 @@
     }
 
     /**
+     * Returns true if there is a route that matches the specified types.
+     * <p>
+     * This method returns true if there are any available routes that match the types
+     * regardless of whether they are enabled or disabled.  If the
+     * {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE} flag is specified, then
+     * the method will only consider non-default routes.
+     * </p>
+     *
+     * @param types The types to match.
+     * @param flags Flags to control the determination of whether a route may be available.
+     * May be zero or {@link #AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE}.
+     * @return True if a matching route may be available.
+     *
+     * @hide Future API ported from support library.  Revisit this later.
+     */
+    public boolean isRouteAvailable(int types, int flags) {
+        final int count = sStatic.mRoutes.size();
+        for (int i = 0; i < count; i++) {
+            RouteInfo route = sStatic.mRoutes.get(i);
+            if (route.matchesTypes(types)) {
+                if ((flags & AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE) == 0
+                        || route != sStatic.mDefaultAudioVideo) {
+                    return true;
+                }
+            }
+        }
+
+        // It doesn't look like we can find a matching route right now.
+        return false;
+    }
+
+    /**
      * Add a callback to listen to events about specific kinds of media routes.
      * If the specified callback is already registered, its registration will be updated for any
      * additional route types specified.
@@ -453,9 +842,7 @@
             info = new CallbackInfo(cb, types, flags, this);
             sStatic.mCallbacks.add(info);
         }
-        if ((info.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
-            sStatic.updateActiveScan();
-        }
+        sStatic.updateDiscoveryRequest();
     }
 
     /**
@@ -466,10 +853,8 @@
     public void removeCallback(Callback cb) {
         int index = findCallbackInfo(cb);
         if (index >= 0) {
-            CallbackInfo info = sStatic.mCallbacks.remove(index);
-            if ((info.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
-                sStatic.updateActiveScan();
-            }
+            sStatic.mCallbacks.remove(index);
+            sStatic.updateDiscoveryRequest();
         } else {
             Log.w(TAG, "removeCallback(" + cb + "): callback not registered");
         }
@@ -499,20 +884,20 @@
      * @param route Route to select
      */
     public void selectRoute(int types, RouteInfo route) {
-        selectRouteStatic(types, route);
+        selectRouteStatic(types, route, true);
     }
-    
+
     /**
      * @hide internal use
      */
-    public void selectRouteInt(int types, RouteInfo route) {
-        selectRouteStatic(types, route);
+    public void selectRouteInt(int types, RouteInfo route, boolean explicit) {
+        selectRouteStatic(types, route, explicit);
     }
 
-    static void selectRouteStatic(int types, RouteInfo route) {
+    static void selectRouteStatic(int types, RouteInfo route, boolean explicit) {
         final RouteInfo oldRoute = sStatic.mSelectedRoute;
         if (oldRoute == route) return;
-        if ((route.getSupportedTypes() & types) == 0) {
+        if (!route.matchesTypes(types)) {
             Log.w(TAG, "selectRoute ignored; cannot select route with supported types " +
                     typesToString(route.getSupportedTypes()) + " into route types " +
                     typesToString(types));
@@ -535,21 +920,43 @@
         final boolean newRouteHasAddress = route != null && route.mDeviceAddress != null;
         if (activeDisplay != null || oldRouteHasAddress || newRouteHasAddress) {
             if (newRouteHasAddress && !matchesDeviceAddress(activeDisplay, route)) {
-                sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress);
+                if (sStatic.mCanConfigureWifiDisplays) {
+                    sStatic.mDisplayService.connectWifiDisplay(route.mDeviceAddress);
+                } else {
+                    Log.e(TAG, "Cannot connect to wifi displays because this process "
+                            + "is not allowed to do so.");
+                }
             } else if (activeDisplay != null && !newRouteHasAddress) {
                 sStatic.mDisplayService.disconnectWifiDisplay();
             }
         }
 
+        sStatic.setSelectedRoute(route, explicit);
+
         if (oldRoute != null) {
             dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute);
+            if (oldRoute.resolveStatusCode()) {
+                dispatchRouteChanged(oldRoute);
+            }
         }
-        sStatic.mSelectedRoute = route;
         if (route != null) {
+            if (route.resolveStatusCode()) {
+                dispatchRouteChanged(route);
+            }
             dispatchRouteSelected(types & route.getSupportedTypes(), route);
         }
     }
 
+    static void selectDefaultRouteStatic() {
+        // TODO: Be smarter about the route types here; this selects for all valid.
+        if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute
+                && sStatic.mBluetoothA2dpRoute != null) {
+            selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
+        } else {
+            selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
+        }
+    }
+
     /**
      * Compare the device address of a display and a route.
      * Nulls/no device address will match another null/no address.
@@ -612,7 +1019,7 @@
      * @see #addUserRoute(UserRouteInfo)
      */
     public void removeUserRoute(UserRouteInfo info) {
-        removeRoute(info);
+        removeRouteStatic(info);
     }
 
     /**
@@ -626,7 +1033,7 @@
             // TODO Right now, RouteGroups only ever contain user routes.
             // The code below will need to change if this assumption does.
             if (info instanceof UserRouteInfo || info instanceof RouteGroup) {
-                removeRouteAt(i);
+                removeRouteStatic(info);
                 i--;
             }
         }
@@ -636,10 +1043,10 @@
      * @hide internal use only
      */
     public void removeRouteInt(RouteInfo info) {
-        removeRoute(info);
+        removeRouteStatic(info);
     }
 
-    static void removeRoute(RouteInfo info) {
+    static void removeRouteStatic(RouteInfo info) {
         if (sStatic.mRoutes.remove(info)) {
             final RouteCategory removingCat = info.getCategory();
             final int count = sStatic.mRoutes.size();
@@ -651,42 +1058,9 @@
                     break;
                 }
             }
-            if (info == sStatic.mSelectedRoute) {
+            if (info.isSelected()) {
                 // Removing the currently selected route? Select the default before we remove it.
-                // TODO: Be smarter about the route types here; this selects for all valid.
-                if (info != sStatic.mBluetoothA2dpRoute && sStatic.mBluetoothA2dpRoute != null) {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
-                            sStatic.mBluetoothA2dpRoute);
-                } else {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
-                            sStatic.mDefaultAudioVideo);
-                }
-            }
-            if (!found) {
-                sStatic.mCategories.remove(removingCat);
-            }
-            dispatchRouteRemoved(info);
-        }
-    }
-
-    void removeRouteAt(int routeIndex) {
-        if (routeIndex >= 0 && routeIndex < sStatic.mRoutes.size()) {
-            final RouteInfo info = sStatic.mRoutes.remove(routeIndex);
-            final RouteCategory removingCat = info.getCategory();
-            final int count = sStatic.mRoutes.size();
-            boolean found = false;
-            for (int i = 0; i < count; i++) {
-                final RouteCategory cat = sStatic.mRoutes.get(i).getCategory();
-                if (removingCat == cat) {
-                    found = true;
-                    break;
-                }
-            }
-            if (info == sStatic.mSelectedRoute) {
-                // Removing the currently selected route? Select the default before we remove it.
-                // TODO: Be smarter about the route types here; this selects for all valid.
-                selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO | ROUTE_TYPE_USER,
-                        sStatic.mDefaultAudioVideo);
+                selectDefaultRouteStatic();
             }
             if (!found) {
                 sStatic.mCategories.remove(removingCat);
@@ -752,7 +1126,7 @@
      *
      * @see #addUserRoute(UserRouteInfo)
      * @see #removeUserRoute(UserRouteInfo)
-     * @see #createRouteCategory(CharSequence)
+     * @see #createRouteCategory(CharSequence, boolean)
      */
     public UserRouteInfo createUserRoute(RouteCategory category) {
         return new UserRouteInfo(category);
@@ -780,6 +1154,23 @@
         return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable);
     }
 
+    /**
+     * Rebinds the media router to handle routes that belong to the specified user.
+     * Requires the interact across users permission to access the routes of another user.
+     * <p>
+     * This method is a complete hack to work around the singleton nature of the
+     * media router when running inside of singleton processes like QuickSettings.
+     * This mechanism should be burned to the ground when MediaRouter is redesigned.
+     * Ideally the current user would be pulled from the Context but we need to break
+     * down MediaRouter.Static before we can get there.
+     * </p>
+     *
+     * @hide
+     */
+    public void rebindAsUser(int userId) {
+        sStatic.rebindAsUser(userId);
+    }
+
     static void updateRoute(final RouteInfo info) {
         dispatchRouteChanged(info);
     }
@@ -801,10 +1192,34 @@
     }
 
     static void dispatchRouteChanged(RouteInfo info) {
+        dispatchRouteChanged(info, info.mSupportedTypes);
+    }
+
+    static void dispatchRouteChanged(RouteInfo info, int oldSupportedTypes) {
+        final int newSupportedTypes = info.mSupportedTypes;
         for (CallbackInfo cbi : sStatic.mCallbacks) {
-            if (cbi.filterRouteEvent(info)) {
+            // Reconstruct some of the history for callbacks that may not have observed
+            // all of the events needed to correctly interpret the current state.
+            // FIXME: This is a strong signal that we should deprecate route type filtering
+            // completely in the future because it can lead to inconsistencies in
+            // applications.
+            final boolean oldVisibility = cbi.filterRouteEvent(oldSupportedTypes);
+            final boolean newVisibility = cbi.filterRouteEvent(newSupportedTypes);
+            if (!oldVisibility && newVisibility) {
+                cbi.cb.onRouteAdded(cbi.router, info);
+                if (info.isSelected()) {
+                    cbi.cb.onRouteSelected(cbi.router, newSupportedTypes, info);
+                }
+            }
+            if (oldVisibility || newVisibility) {
                 cbi.cb.onRouteChanged(cbi.router, info);
             }
+            if (oldVisibility && !newVisibility) {
+                if (info.isSelected()) {
+                    cbi.cb.onRouteUnselected(cbi.router, oldSupportedTypes, info);
+                }
+                cbi.cb.onRouteRemoved(cbi.router, info);
+            }
         }
     }
 
@@ -875,65 +1290,73 @@
         }
     }
 
-    static void updateWifiDisplayStatus(WifiDisplayStatus newStatus) {
-        final WifiDisplayStatus oldStatus = sStatic.mLastKnownWifiDisplayStatus;
-
-        // TODO Naive implementation. Make this smarter later.
+    static void updateWifiDisplayStatus(WifiDisplayStatus status) {
         boolean wantScan = false;
-        boolean blockScan = false;
-        WifiDisplay[] oldDisplays = oldStatus != null ?
-                oldStatus.getDisplays() : WifiDisplay.EMPTY_ARRAY;
-        WifiDisplay[] newDisplays;
+        WifiDisplay[] displays;
         WifiDisplay activeDisplay;
 
-        if (newStatus.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
-            newDisplays = newStatus.getDisplays();
-            activeDisplay = newStatus.getActiveDisplay();
+        if (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON) {
+            displays = status.getDisplays();
+            activeDisplay = status.getActiveDisplay();
+
+            // Only the system is able to connect to wifi display routes.
+            // The display manager will enforce this with a permission check but it
+            // still publishes information about all available displays.
+            // Filter the list down to just the active display.
+            if (!sStatic.mCanConfigureWifiDisplays) {
+                if (activeDisplay != null) {
+                    displays = new WifiDisplay[] { activeDisplay };
+                } else {
+                    displays = WifiDisplay.EMPTY_ARRAY;
+                }
+            }
         } else {
-            newDisplays = WifiDisplay.EMPTY_ARRAY;
+            displays = WifiDisplay.EMPTY_ARRAY;
             activeDisplay = null;
         }
 
-        for (int i = 0; i < newDisplays.length; i++) {
-            final WifiDisplay d = newDisplays[i];
-            if (d.isRemembered()) {
+        // Add or update routes.
+        for (int i = 0; i < displays.length; i++) {
+            final WifiDisplay d = displays[i];
+            if (shouldShowWifiDisplay(d, activeDisplay)) {
                 RouteInfo route = findWifiDisplayRoute(d);
                 if (route == null) {
-                    route = makeWifiDisplayRoute(d, newStatus);
+                    route = makeWifiDisplayRoute(d, status);
                     addRouteStatic(route);
                     wantScan = true;
                 } else {
-                    updateWifiDisplayRoute(route, d, newStatus);
+                    updateWifiDisplayRoute(route, d, status);
                 }
                 if (d.equals(activeDisplay)) {
-                    selectRouteStatic(route.getSupportedTypes(), route);
-
-                    // Don't scan if we're already connected to a wifi display,
-                    // the scanning process can cause a hiccup with some configurations.
-                    blockScan = true;
-                }
-            }
-        }
-        for (int i = 0; i < oldDisplays.length; i++) {
-            final WifiDisplay d = oldDisplays[i];
-            if (d.isRemembered()) {
-                final WifiDisplay newDisplay = findMatchingDisplay(d, newDisplays);
-                if (newDisplay == null || !newDisplay.isRemembered()) {
-                    removeRoute(findWifiDisplayRoute(d));
+                    selectRouteStatic(route.getSupportedTypes(), route, false);
                 }
             }
         }
 
-        if (wantScan && !blockScan) {
+        // Remove stale routes.
+        for (int i = sStatic.mRoutes.size(); i-- > 0; ) {
+            RouteInfo route = sStatic.mRoutes.get(i);
+            if (route.mDeviceAddress != null) {
+                WifiDisplay d = findWifiDisplay(displays, route.mDeviceAddress);
+                if (d == null || !shouldShowWifiDisplay(d, activeDisplay)) {
+                    removeRouteStatic(route);
+                }
+            }
+        }
+
+        // Don't scan if we're already connected to a wifi display,
+        // the scanning process can cause a hiccup with some configurations.
+        if (wantScan && activeDisplay != null && sStatic.mCanConfigureWifiDisplays) {
             sStatic.mDisplayService.scanWifiDisplays();
         }
+    }
 
-        sStatic.mLastKnownWifiDisplayStatus = newStatus;
+    private static boolean shouldShowWifiDisplay(WifiDisplay d, WifiDisplay activeDisplay) {
+        return d.isRemembered() || d.equals(activeDisplay);
     }
 
     static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) {
-        int newStatus = RouteInfo.STATUS_NONE;
-
+        int newStatus;
         if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) {
             newStatus = RouteInfo.STATUS_SCANNING;
         } else if (d.isAvailable()) {
@@ -947,7 +1370,7 @@
             final int activeState = wfdStatus.getActiveDisplayState();
             switch (activeState) {
                 case WifiDisplayStatus.DISPLAY_STATE_CONNECTED:
-                    newStatus = RouteInfo.STATUS_NONE;
+                    newStatus = RouteInfo.STATUS_CONNECTED;
                     break;
                 case WifiDisplayStatus.DISPLAY_STATE_CONNECTING:
                     newStatus = RouteInfo.STATUS_CONNECTING;
@@ -968,18 +1391,17 @@
     static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) {
         final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory);
         newRoute.mDeviceAddress = display.getDeviceAddress();
-        newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
+        newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO
+                | ROUTE_TYPE_REMOTE_DISPLAY;
         newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
         newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE;
 
-        newRoute.setStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
+        newRoute.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
         newRoute.mEnabled = isWifiDisplayEnabled(display, wfdStatus);
         newRoute.mName = display.getFriendlyDisplayName();
         newRoute.mDescription = sStatic.mResources.getText(
                 com.android.internal.R.string.wireless_display_route_description);
-
-        newRoute.mPresentationDisplay = choosePresentationDisplayForRoute(newRoute,
-                sStatic.getAllPresentationDisplays());
+        newRoute.updatePresentationDisplay();
         return newRoute;
     }
 
@@ -996,24 +1418,23 @@
         changed |= route.mEnabled != enabled;
         route.mEnabled = enabled;
 
-        changed |= route.setStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
+        changed |= route.setRealStatusCode(getWifiDisplayStatusCode(display, wfdStatus));
 
         if (changed) {
             dispatchRouteChanged(route);
         }
 
-        if (!enabled && route == sStatic.mSelectedRoute) {
+        if (!enabled && route.isSelected()) {
             // Oops, no longer available. Reselect the default.
-            final RouteInfo defaultRoute = sStatic.mDefaultAudioVideo;
-            selectRouteStatic(defaultRoute.getSupportedTypes(), defaultRoute);
+            selectDefaultRouteStatic();
         }
     }
 
-    private static WifiDisplay findMatchingDisplay(WifiDisplay d, WifiDisplay[] displays) {
+    private static WifiDisplay findWifiDisplay(WifiDisplay[] displays, String deviceAddress) {
         for (int i = 0; i < displays.length; i++) {
-            final WifiDisplay other = displays[i];
-            if (d.hasSameAddress(other)) {
-                return other;
+            final WifiDisplay d = displays[i];
+            if (d.getDeviceAddress().equals(deviceAddress)) {
+                return d;
             }
         }
         return null;
@@ -1030,27 +1451,6 @@
         return null;
     }
 
-    private static Display choosePresentationDisplayForRoute(RouteInfo route, Display[] displays) {
-        if ((route.mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) {
-            if (route.mDeviceAddress != null) {
-                // Find the indicated Wifi display by its address.
-                for (Display display : displays) {
-                    if (display.getType() == Display.TYPE_WIFI
-                            && route.mDeviceAddress.equals(display.getAddress())) {
-                        return display;
-                    }
-                }
-                return null;
-            }
-
-            if (route == sStatic.mDefaultAudioVideo && displays.length > 0) {
-                // Choose the first presentation display from the list.
-                return displays[0];
-            }
-        }
-        return null;
-    }
-
     /**
      * Information about a media route.
      */
@@ -1071,12 +1471,18 @@
         int mPlaybackStream = AudioManager.STREAM_MUSIC;
         VolumeCallbackInfo mVcb;
         Display mPresentationDisplay;
+        int mPresentationDisplayId = -1;
 
         String mDeviceAddress;
         boolean mEnabled = true;
 
+        // An id by which the route is known to the media router service.
+        // Null if this route only exists as an artifact within this process.
+        String mGlobalRouteId;
+
         // A predetermined connection status that can override mStatus
-        private int mStatusCode;
+        private int mRealStatusCode;
+        private int mResolvedStatusCode;
 
         /** @hide */ public static final int STATUS_NONE = 0;
         /** @hide */ public static final int STATUS_SCANNING = 1;
@@ -1084,19 +1490,20 @@
         /** @hide */ public static final int STATUS_AVAILABLE = 3;
         /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4;
         /** @hide */ public static final int STATUS_IN_USE = 5;
+        /** @hide */ public static final int STATUS_CONNECTED = 6;
 
         private Object mTag;
 
         /**
          * 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)
+         * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_LOCAL = 0;
         /**
          * 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)
+         * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_REMOTE = 1;
         /**
@@ -1104,12 +1511,13 @@
          * 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)
+         * @see #getVolumeHandling()
          */
         public final static int PLAYBACK_VOLUME_FIXED = 0;
         /**
          * Playback information indicating the playback volume is variable and can be controlled
          * from this object.
+         * @see #getVolumeHandling()
          */
         public final static int PLAYBACK_VOLUME_VARIABLE = 1;
 
@@ -1178,38 +1586,71 @@
          * Set this route's status by predetermined status code. If the caller
          * should dispatch a route changed event this call will return true;
          */
-        boolean setStatusCode(int statusCode) {
-            if (statusCode != mStatusCode) {
-                mStatusCode = statusCode;
-                int resId = 0;
-                switch (statusCode) {
-                    case STATUS_SCANNING:
-                        resId = com.android.internal.R.string.media_route_status_scanning;
-                        break;
-                    case STATUS_CONNECTING:
-                        resId = com.android.internal.R.string.media_route_status_connecting;
-                        break;
-                    case STATUS_AVAILABLE:
-                        resId = com.android.internal.R.string.media_route_status_available;
-                        break;
-                    case STATUS_NOT_AVAILABLE:
-                        resId = com.android.internal.R.string.media_route_status_not_available;
-                        break;
-                    case STATUS_IN_USE:
-                        resId = com.android.internal.R.string.media_route_status_in_use;
-                        break;
-                }
-                mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null;
-                return true;
+        boolean setRealStatusCode(int statusCode) {
+            if (mRealStatusCode != statusCode) {
+                mRealStatusCode = statusCode;
+                return resolveStatusCode();
             }
             return false;
         }
 
         /**
+         * Resolves the status code whenever the real status code or selection state
+         * changes.
+         */
+        boolean resolveStatusCode() {
+            int statusCode = mRealStatusCode;
+            if (isSelected()) {
+                switch (statusCode) {
+                    // If the route is selected and its status appears to be between states
+                    // then report it as connecting even though it has not yet had a chance
+                    // to officially move into the CONNECTING state.  Note that routes in
+                    // the NONE state are assumed to not require an explicit connection
+                    // lifecycle whereas those that are AVAILABLE are assumed to have
+                    // to eventually proceed to CONNECTED.
+                    case STATUS_AVAILABLE:
+                    case STATUS_SCANNING:
+                        statusCode = STATUS_CONNECTING;
+                        break;
+                }
+            }
+            if (mResolvedStatusCode == statusCode) {
+                return false;
+            }
+
+            mResolvedStatusCode = statusCode;
+            int resId;
+            switch (statusCode) {
+                case STATUS_SCANNING:
+                    resId = com.android.internal.R.string.media_route_status_scanning;
+                    break;
+                case STATUS_CONNECTING:
+                    resId = com.android.internal.R.string.media_route_status_connecting;
+                    break;
+                case STATUS_AVAILABLE:
+                    resId = com.android.internal.R.string.media_route_status_available;
+                    break;
+                case STATUS_NOT_AVAILABLE:
+                    resId = com.android.internal.R.string.media_route_status_not_available;
+                    break;
+                case STATUS_IN_USE:
+                    resId = com.android.internal.R.string.media_route_status_in_use;
+                    break;
+                case STATUS_CONNECTED:
+                case STATUS_NONE:
+                default:
+                    resId = 0;
+                    break;
+            }
+            mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null;
+            return true;
+        }
+
+        /**
          * @hide
          */
         public int getStatusCode() {
-            return mStatusCode;
+            return mResolvedStatusCode;
         }
 
         /**
@@ -1219,6 +1660,11 @@
             return mSupportedTypes;
         }
 
+        /** @hide */
+        public boolean matchesTypes(int types) {
+            return (mSupportedTypes & types) != 0;
+        }
+
         /**
          * @return The group that this route belongs to.
          */
@@ -1317,9 +1763,7 @@
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
             } else {
-                Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " +
-                        "Non-local volume playback on system route? " +
-                        "Could not request volume change.");
+                sStatic.requestSetVolume(this, volume);
             }
         }
 
@@ -1338,9 +1782,7 @@
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
             } else {
-                Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " +
-                        "Non-local volume playback on system route? " +
-                        "Could not request volume change.");
+                sStatic.requestUpdateVolume(this, direction);
             }
         }
 
@@ -1402,6 +1844,55 @@
             return mPresentationDisplay;
         }
 
+        boolean updatePresentationDisplay() {
+            Display display = choosePresentationDisplay();
+            if (mPresentationDisplay != display) {
+                mPresentationDisplay = display;
+                return true;
+            }
+            return false;
+        }
+
+        private Display choosePresentationDisplay() {
+            if ((mSupportedTypes & ROUTE_TYPE_LIVE_VIDEO) != 0) {
+                Display[] displays = sStatic.getAllPresentationDisplays();
+
+                // Ensure that the specified display is valid for presentations.
+                // This check will normally disallow the default display unless it was
+                // configured as a presentation display for some reason.
+                if (mPresentationDisplayId >= 0) {
+                    for (Display display : displays) {
+                        if (display.getDisplayId() == mPresentationDisplayId) {
+                            return display;
+                        }
+                    }
+                    return null;
+                }
+
+                // Find the indicated Wifi display by its address.
+                if (mDeviceAddress != null) {
+                    for (Display display : displays) {
+                        if (display.getType() == Display.TYPE_WIFI
+                                && mDeviceAddress.equals(display.getAddress())) {
+                            return display;
+                        }
+                    }
+                    return null;
+                }
+
+                // For the default route, choose the first presentation display from the list.
+                if (this == sStatic.mDefaultAudioVideo && displays.length > 0) {
+                    return displays[0];
+                }
+            }
+            return null;
+        }
+
+        /** @hide */
+        public String getDeviceAddress() {
+            return mDeviceAddress;
+        }
+
         /**
          * Returns true if this route is enabled and may be selected.
          *
@@ -1418,7 +1909,22 @@
          * @return True if this route is in the process of connecting.
          */
         public boolean isConnecting() {
-            return mStatusCode == STATUS_CONNECTING;
+            return mResolvedStatusCode == STATUS_CONNECTING;
+        }
+
+        /** @hide */
+        public boolean isSelected() {
+            return this == sStatic.mSelectedRoute;
+        }
+
+        /** @hide */
+        public boolean isDefault() {
+            return this == sStatic.mDefaultAudioVideo;
+        }
+
+        /** @hide */
+        public void select() {
+            selectRouteStatic(mSupportedTypes, this, true);
         }
 
         void setStatusInt(CharSequence status) {
@@ -1432,6 +1938,7 @@
         }
 
         final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() {
+            @Override
             public void dispatchRemoteVolumeUpdate(final int direction, final int value) {
                 sStatic.mHandler.post(new Runnable() {
                     @Override
@@ -1460,7 +1967,7 @@
                     ", status=" + getStatus() +
                     ", category=" + getCategory() +
                     ", supportedTypes=" + supportedTypes +
-                    ", presentationDisplay=" + mPresentationDisplay + "}";
+                    ", presentationDisplay=" + mPresentationDisplay + " }";
         }
     }
 
@@ -1716,6 +2223,7 @@
             mVolumeHandling = PLAYBACK_VOLUME_FIXED;
         }
 
+        @Override
         CharSequence getName(Resources res) {
             if (mUpdateName) updateName();
             return super.getName(res);
@@ -1916,7 +2424,7 @@
             final int count = mRoutes.size();
             if (count == 0) {
                 // Don't keep empty groups in the router.
-                MediaRouter.removeRoute(this);
+                MediaRouter.removeRouteStatic(this);
                 return;
             }
 
@@ -2071,6 +2579,7 @@
             return mIsSystem;
         }
 
+        @Override
         public String toString() {
             return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) +
                     " groupable=" + mGroupable + " }";
@@ -2091,8 +2600,12 @@
         }
 
         public boolean filterRouteEvent(RouteInfo route) {
+            return filterRouteEvent(route.mSupportedTypes);
+        }
+
+        public boolean filterRouteEvent(int supportedTypes) {
             return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0
-                    || (type & route.mSupportedTypes) != 0;
+                    || (type & supportedTypes) != 0;
         }
     }
 
diff --git a/media/java/android/media/MediaRouterClientState.aidl b/media/java/android/media/MediaRouterClientState.aidl
new file mode 100644
index 0000000..70077119
--- /dev/null
+++ b/media/java/android/media/MediaRouterClientState.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2013, 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;
+
+parcelable MediaRouterClientState;
diff --git a/media/java/android/media/MediaRouterClientState.java b/media/java/android/media/MediaRouterClientState.java
new file mode 100644
index 0000000..54b8276
--- /dev/null
+++ b/media/java/android/media/MediaRouterClientState.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013 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;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+/**
+ * Information available from MediaRouterService about the state perceived by
+ * a particular client and the routes that are available to it.
+ *
+ * Clients must not modify the contents of this object.
+ * @hide
+ */
+public final class MediaRouterClientState implements Parcelable {
+    /**
+     * A list of all known routes.
+     */
+    public final ArrayList<RouteInfo> routes;
+
+    /**
+     * The id of the current globally selected route, or null if none.
+     * Globally selected routes override any other route selections that applications
+     * may have made.  Used for remote displays.
+     */
+    public String globallySelectedRouteId;
+
+    public MediaRouterClientState() {
+        routes = new ArrayList<RouteInfo>();
+    }
+
+    MediaRouterClientState(Parcel src) {
+        routes = src.createTypedArrayList(RouteInfo.CREATOR);
+        globallySelectedRouteId = src.readString();
+    }
+
+    public RouteInfo getRoute(String id) {
+        final int count = routes.size();
+        for (int i = 0; i < count; i++) {
+            final RouteInfo route = routes.get(i);
+            if (route.id.equals(id)) {
+                return route;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(routes);
+        dest.writeString(globallySelectedRouteId);
+    }
+
+    @Override
+    public String toString() {
+        return "MediaRouterClientState{ globallySelectedRouteId="
+                + globallySelectedRouteId + ", routes=" + routes.toString() + " }";
+    }
+
+    public static final Parcelable.Creator<MediaRouterClientState> CREATOR =
+            new Parcelable.Creator<MediaRouterClientState>() {
+        @Override
+        public MediaRouterClientState createFromParcel(Parcel in) {
+            return new MediaRouterClientState(in);
+        }
+
+        @Override
+        public MediaRouterClientState[] newArray(int size) {
+            return new MediaRouterClientState[size];
+        }
+    };
+
+    public static final class RouteInfo implements Parcelable {
+        public String id;
+        public String name;
+        public String description;
+        public int supportedTypes;
+        public boolean enabled;
+        public int statusCode;
+        public int playbackType;
+        public int playbackStream;
+        public int volume;
+        public int volumeMax;
+        public int volumeHandling;
+        public int presentationDisplayId;
+
+        public RouteInfo(String id) {
+            this.id = id;
+            enabled = true;
+            statusCode = MediaRouter.RouteInfo.STATUS_NONE;
+            playbackType = MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+            playbackStream = -1;
+            volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+            presentationDisplayId = -1;
+        }
+
+        public RouteInfo(RouteInfo other) {
+            id = other.id;
+            name = other.name;
+            description = other.description;
+            supportedTypes = other.supportedTypes;
+            enabled = other.enabled;
+            statusCode = other.statusCode;
+            playbackType = other.playbackType;
+            playbackStream = other.playbackStream;
+            volume = other.volume;
+            volumeMax = other.volumeMax;
+            volumeHandling = other.volumeHandling;
+            presentationDisplayId = other.presentationDisplayId;
+        }
+
+        RouteInfo(Parcel in) {
+            id = in.readString();
+            name = in.readString();
+            description = in.readString();
+            supportedTypes = in.readInt();
+            enabled = in.readInt() != 0;
+            statusCode = in.readInt();
+            playbackType = in.readInt();
+            playbackStream = in.readInt();
+            volume = in.readInt();
+            volumeMax = in.readInt();
+            volumeHandling = in.readInt();
+            presentationDisplayId = in.readInt();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(id);
+            dest.writeString(name);
+            dest.writeString(description);
+            dest.writeInt(supportedTypes);
+            dest.writeInt(enabled ? 1 : 0);
+            dest.writeInt(statusCode);
+            dest.writeInt(playbackType);
+            dest.writeInt(playbackStream);
+            dest.writeInt(volume);
+            dest.writeInt(volumeMax);
+            dest.writeInt(volumeHandling);
+            dest.writeInt(presentationDisplayId);
+        }
+
+        @Override
+        public String toString() {
+            return "RouteInfo{ id=" + id
+                    + ", name=" + name
+                    + ", description=" + description
+                    + ", supportedTypes=0x" + Integer.toHexString(supportedTypes)
+                    + ", enabled=" + enabled
+                    + ", statusCode=" + statusCode
+                    + ", playbackType=" + playbackType
+                    + ", playbackStream=" + playbackStream
+                    + ", volume=" + volume
+                    + ", volumeMax=" + volumeMax
+                    + ", volumeHandling=" + volumeHandling
+                    + ", presentationDisplayId=" + presentationDisplayId
+                    + " }";
+        }
+
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<RouteInfo> CREATOR =
+                new Parcelable.Creator<RouteInfo>() {
+            @Override
+            public RouteInfo createFromParcel(Parcel in) {
+                return new RouteInfo(in);
+            }
+
+            @Override
+            public RouteInfo[] newArray(int size) {
+                return new RouteInfo[size];
+            }
+        };
+    }
+}
diff --git a/media/java/android/media/RemoteDisplayState.aidl b/media/java/android/media/RemoteDisplayState.aidl
new file mode 100644
index 0000000..b3262fc
--- /dev/null
+++ b/media/java/android/media/RemoteDisplayState.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2013, 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;
+
+parcelable RemoteDisplayState;
diff --git a/media/java/android/media/RemoteDisplayState.java b/media/java/android/media/RemoteDisplayState.java
new file mode 100644
index 0000000..1197f65
--- /dev/null
+++ b/media/java/android/media/RemoteDisplayState.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2013 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;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Information available from IRemoteDisplayProvider about available remote displays.
+ *
+ * Clients must not modify the contents of this object.
+ * @hide
+ */
+public final class RemoteDisplayState implements Parcelable {
+    // Note: These constants are used by the remote display provider API.
+    // Do not change them!
+    public static final String SERVICE_INTERFACE =
+            "com.android.media.remotedisplay.RemoteDisplayProvider";
+    public static final int DISCOVERY_MODE_NONE = 0;
+    public static final int DISCOVERY_MODE_PASSIVE = 1;
+    public static final int DISCOVERY_MODE_ACTIVE = 2;
+
+    /**
+     * A list of all remote displays.
+     */
+    public final ArrayList<RemoteDisplayInfo> displays;
+
+    public RemoteDisplayState() {
+        displays = new ArrayList<RemoteDisplayInfo>();
+    }
+
+    RemoteDisplayState(Parcel src) {
+        displays = src.createTypedArrayList(RemoteDisplayInfo.CREATOR);
+    }
+
+    public boolean isValid() {
+        if (displays == null) {
+            return false;
+        }
+        final int count = displays.size();
+        for (int i = 0; i < count; i++) {
+            if (!displays.get(i).isValid()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(displays);
+    }
+
+    public static final Parcelable.Creator<RemoteDisplayState> CREATOR =
+            new Parcelable.Creator<RemoteDisplayState>() {
+        @Override
+        public RemoteDisplayState createFromParcel(Parcel in) {
+            return new RemoteDisplayState(in);
+        }
+
+        @Override
+        public RemoteDisplayState[] newArray(int size) {
+            return new RemoteDisplayState[size];
+        }
+    };
+
+    public static final class RemoteDisplayInfo implements Parcelable {
+        // Note: These constants are used by the remote display provider API.
+        // Do not change them!
+        public static final int STATUS_NOT_AVAILABLE = 0;
+        public static final int STATUS_IN_USE = 1;
+        public static final int STATUS_AVAILABLE = 2;
+        public static final int STATUS_CONNECTING = 3;
+        public static final int STATUS_CONNECTED = 4;
+
+        public static final int PLAYBACK_VOLUME_VARIABLE =
+                MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+        public static final int PLAYBACK_VOLUME_FIXED =
+                MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+
+        public String id;
+        public String name;
+        public String description;
+        public int status;
+        public int volume;
+        public int volumeMax;
+        public int volumeHandling;
+        public int presentationDisplayId;
+
+        public RemoteDisplayInfo(String id) {
+            this.id = id;
+            status = STATUS_NOT_AVAILABLE;
+            volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+            presentationDisplayId = -1;
+        }
+
+        public RemoteDisplayInfo(RemoteDisplayInfo other) {
+            id = other.id;
+            name = other.name;
+            description = other.description;
+            status = other.status;
+            volume = other.volume;
+            volumeMax = other.volumeMax;
+            volumeHandling = other.volumeHandling;
+            presentationDisplayId = other.presentationDisplayId;
+        }
+
+        RemoteDisplayInfo(Parcel in) {
+            id = in.readString();
+            name = in.readString();
+            description = in.readString();
+            status = in.readInt();
+            volume = in.readInt();
+            volumeMax = in.readInt();
+            volumeHandling = in.readInt();
+            presentationDisplayId = in.readInt();
+        }
+
+        public boolean isValid() {
+            return !TextUtils.isEmpty(id) && !TextUtils.isEmpty(name);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(id);
+            dest.writeString(name);
+            dest.writeString(description);
+            dest.writeInt(status);
+            dest.writeInt(volume);
+            dest.writeInt(volumeMax);
+            dest.writeInt(volumeHandling);
+            dest.writeInt(presentationDisplayId);
+        }
+
+        @Override
+        public String toString() {
+            return "RemoteDisplayInfo{ id=" + id
+                    + ", name=" + name
+                    + ", description=" + description
+                    + ", status=" + status
+                    + ", volume=" + volume
+                    + ", volumeMax=" + volumeMax
+                    + ", volumeHandling=" + volumeHandling
+                    + ", presentationDisplayId=" + presentationDisplayId
+                    + " }";
+        }
+
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<RemoteDisplayInfo> CREATOR =
+                new Parcelable.Creator<RemoteDisplayInfo>() {
+            @Override
+            public RemoteDisplayInfo createFromParcel(Parcel in) {
+                return new RemoteDisplayInfo(in);
+            }
+
+            @Override
+            public RemoteDisplayInfo[] newArray(int size) {
+                return new RemoteDisplayInfo[size];
+            }
+        };
+    }
+}
diff --git a/media/lib/Android.mk b/media/lib/Android.mk
new file mode 100644
index 0000000..50799a6
--- /dev/null
+++ b/media/lib/Android.mk
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2013 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+# the library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= com.android.media.remotedisplay
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+            $(call all-subdir-java-files) \
+            $(call all-aidl-files-under, java)
+
+include $(BUILD_JAVA_LIBRARY)
+
+
+# ====  com.android.media.remotedisplay.xml lib def  ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := com.android.media.remotedisplay.xml
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/media/lib/README.txt b/media/lib/README.txt
new file mode 100644
index 0000000..cade3df
--- /dev/null
+++ b/media/lib/README.txt
@@ -0,0 +1,28 @@
+This library (com.android.media.remotedisplay.jar) is a shared java library
+containing classes required by unbundled remote display providers.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled remote display providers
+  that may be distributed outside the system image. So it MUST BE API STABLE.
+  You can add but not remove. The rules are the same as for the
+  public platform SDK API.
+o This library can see and instantiate internal platform classes, but it must not
+  expose them in any public method (or by extending them via inheritance). This would
+  break clients of the library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exists? ---
+
+Unbundled remote display providers (such as Cast) cannot use internal
+platform classes.
+
+This library will eventually be replaced when the media route provider
+infrastructure that is currently defined in the support library is reintegrated
+with the framework in a new API.  That API isn't ready yet so this
+library is a compromise to make new capabilities available to the system
+without exposing the full surface area of the support library media
+route provider protocol.
+
diff --git a/media/lib/com.android.media.remotedisplay.xml b/media/lib/com.android.media.remotedisplay.xml
new file mode 100644
index 0000000..77a91d2
--- /dev/null
+++ b/media/lib/com.android.media.remotedisplay.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<permissions>
+    <library name="com.android.media.remotedisplay"
+            file="/system/framework/com.android.media.remotedisplay.jar" />
+</permissions>
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
new file mode 100644
index 0000000..5e15702
--- /dev/null
+++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 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.android.media.remotedisplay;
+
+import com.android.internal.util.Objects;
+
+import android.media.MediaRouter;
+import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.text.TextUtils;
+
+/**
+ * Represents a remote display that has been discovered.
+ */
+public class RemoteDisplay {
+    private final RemoteDisplayInfo mMutableInfo;
+    private RemoteDisplayInfo mImmutableInfo;
+
+    /**
+     * Status code: Indicates that the remote display is not available.
+     */
+    public static final int STATUS_NOT_AVAILABLE = RemoteDisplayInfo.STATUS_NOT_AVAILABLE;
+
+    /**
+     * Status code: Indicates that the remote display is in use by someone else.
+     */
+    public static final int STATUS_IN_USE = RemoteDisplayInfo.STATUS_IN_USE;
+
+    /**
+     * Status code: Indicates that the remote display is available for new connections.
+     */
+    public static final int STATUS_AVAILABLE = RemoteDisplayInfo.STATUS_AVAILABLE;
+
+    /**
+     * Status code: Indicates that the remote display is current connecting.
+     */
+    public static final int STATUS_CONNECTING = RemoteDisplayInfo.STATUS_CONNECTING;
+
+    /**
+     * Status code: Indicates that the remote display is connected and is mirroring
+     * display contents.
+     */
+    public static final int STATUS_CONNECTED = RemoteDisplayInfo.STATUS_CONNECTED;
+
+    /**
+     * Volume handling: Output volume can be changed.
+     */
+    public static final int PLAYBACK_VOLUME_VARIABLE =
+            RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE;
+
+    /**
+     * Volume handling: Output volume is fixed.
+     */
+    public static final int PLAYBACK_VOLUME_FIXED =
+            RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED;
+
+    /**
+     * Creates a remote display with the specified name and id.
+     */
+    public RemoteDisplay(String id, String name) {
+        if (TextUtils.isEmpty(id)) {
+            throw new IllegalArgumentException("id must not be null or empty");
+        }
+        mMutableInfo = new RemoteDisplayInfo(id);
+        setName(name);
+    }
+
+    public String getId() {
+        return mMutableInfo.id;
+    }
+
+    public String getName() {
+        return mMutableInfo.name;
+    }
+
+    public void setName(String name) {
+        if (!Objects.equal(mMutableInfo.name, name)) {
+            mMutableInfo.name = name;
+            mImmutableInfo = null;
+        }
+    }
+
+    public String getDescription() {
+        return mMutableInfo.description;
+    }
+
+    public void setDescription(String description) {
+        if (!Objects.equal(mMutableInfo.description, description)) {
+            mMutableInfo.description = description;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getStatus() {
+        return mMutableInfo.status;
+    }
+
+    public void setStatus(int status) {
+        if (mMutableInfo.status != status) {
+            mMutableInfo.status = status;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getVolume() {
+        return mMutableInfo.volume;
+    }
+
+    public void setVolume(int volume) {
+        if (mMutableInfo.volume != volume) {
+            mMutableInfo.volume = volume;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getVolumeMax() {
+        return mMutableInfo.volumeMax;
+    }
+
+    public void setVolumeMax(int volumeMax) {
+        if (mMutableInfo.volumeMax != volumeMax) {
+            mMutableInfo.volumeMax = volumeMax;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getVolumeHandling() {
+        return mMutableInfo.volumeHandling;
+    }
+
+    public void setVolumeHandling(int volumeHandling) {
+        if (mMutableInfo.volumeHandling != volumeHandling) {
+            mMutableInfo.volumeHandling = volumeHandling;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getPresentationDisplayId() {
+        return mMutableInfo.presentationDisplayId;
+    }
+
+    public void setPresentationDisplayId(int presentationDisplayId) {
+        if (mMutableInfo.presentationDisplayId != presentationDisplayId) {
+            mMutableInfo.presentationDisplayId = presentationDisplayId;
+            mImmutableInfo = null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "RemoteDisplay{" + mMutableInfo.toString() + "}";
+    }
+
+    RemoteDisplayInfo getInfo() {
+        if (mImmutableInfo == null) {
+            mImmutableInfo = new RemoteDisplayInfo(mMutableInfo);
+        }
+        return mImmutableInfo;
+    }
+}
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
new file mode 100644
index 0000000..e2df77c
--- /dev/null
+++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2013 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.android.media.remotedisplay;
+
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.media.IRemoteDisplayCallback;
+import android.media.IRemoteDisplayProvider;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.ArrayMap;
+
+import java.util.Collection;
+
+/**
+ * Base class for remote display providers implemented as unbundled services.
+ * <p>
+ * To implement your remote display provider service, create a subclass of
+ * {@link Service} and override the {@link Service#onBind Service.onBind()} method
+ * to return the provider's binder when the {@link #SERVICE_INTERFACE} is requested.
+ * </p>
+ * <pre>
+ *   public class SampleRemoteDisplayProviderService extends Service {
+ *       private SampleProvider mProvider;
+ *
+ *       public IBinder onBind(Intent intent) {
+ *           if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
+ *               if (mProvider == null) {
+ *                   mProvider = new SampleProvider(this);
+ *               }
+ *               return mProvider.getBinder();
+ *           }
+ *           return null;
+ *       }
+ *
+ *       class SampleProvider extends RemoteDisplayProvider {
+ *           public SampleProvider() {
+ *               super(SampleRemoteDisplayProviderService.this);
+ *           }
+ *
+ *           // --- Implementation goes here ---
+ *       }
+ *   }
+ * </pre>
+ * <p>
+ * Declare your remote display provider service in your application manifest
+ * like this:
+ * </p>
+ * <pre>
+ *   &lt;application>
+ *       &lt;uses-library android:name="com.android.media.remotedisplay" />
+ *
+ *       &lt;service android:name=".SampleRemoteDisplayProviderService"
+ *               android:label="@string/sample_remote_display_provider_service"
+ *               android:exported="true"
+ *               android:permission="android.permission.BIND_REMOTE_DISPLAY">
+ *           &lt;intent-filter>
+ *               &lt;action android:name="com.android.media.remotedisplay.RemoteDisplayProvider" />
+ *           &lt;/intent-filter>
+ *       &lt;/service>
+ *   &lt;/application>
+ * </pre>
+ * <p>
+ * This object is not thread safe.  It is only intended to be accessed on the
+ * {@link Context#getMainLooper main looper thread} of an application.
+ * </p><p>
+ * IMPORTANT: This class is effectively a public API for unbundled applications, and
+ * must remain API stable. See README.txt in the root of this package for more information.
+ * </p>
+ */
+public abstract class RemoteDisplayProvider {
+    private static final int MSG_SET_CALLBACK = 1;
+    private static final int MSG_SET_DISCOVERY_MODE = 2;
+    private static final int MSG_CONNECT = 3;
+    private static final int MSG_DISCONNECT = 4;
+    private static final int MSG_SET_VOLUME = 5;
+    private static final int MSG_ADJUST_VOLUME = 6;
+
+    private final Context mContext;
+    private final ProviderStub mStub;
+    private final ProviderHandler mHandler;
+    private final ArrayMap<String, RemoteDisplay> mDisplays =
+            new ArrayMap<String, RemoteDisplay>();
+    private IRemoteDisplayCallback mCallback;
+    private int mDiscoveryMode = DISCOVERY_MODE_NONE;
+
+    private PendingIntent mSettingsPendingIntent;
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     * Put this in your manifest.
+     */
+    public static final String SERVICE_INTERFACE = RemoteDisplayState.SERVICE_INTERFACE;
+
+    /**
+     * Discovery mode: Do not perform any discovery.
+     */
+    public static final int DISCOVERY_MODE_NONE = RemoteDisplayState.DISCOVERY_MODE_NONE;
+
+    /**
+     * Discovery mode: Passive or low-power periodic discovery.
+     * <p>
+     * This mode indicates that an application is interested in knowing whether there
+     * are any remote displays paired or available but doesn't need the latest or
+     * most detailed information.  The provider may scan at a lower rate or rely on
+     * knowledge of previously paired devices.
+     * </p>
+     */
+    public static final int DISCOVERY_MODE_PASSIVE = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
+
+    /**
+     * Discovery mode: Active discovery.
+     * <p>
+     * This mode indicates that the user is actively trying to connect to a route
+     * and we should perform continuous scans.  This mode may use significantly more
+     * power but is intended to be short-lived.
+     * </p>
+     */
+    public static final int DISCOVERY_MODE_ACTIVE = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
+
+    /**
+     * Creates a remote display provider.
+     *
+     * @param context The application context for the remote display provider.
+     */
+    public RemoteDisplayProvider(Context context) {
+        mContext = context;
+        mStub = new ProviderStub();
+        mHandler = new ProviderHandler(context.getMainLooper());
+    }
+
+    /**
+     * Gets the context of the remote display provider.
+     */
+    public final Context getContext() {
+        return mContext;
+    }
+
+    /**
+     * Gets the Binder associated with the provider.
+     * <p>
+     * This is intended to be used for the onBind() method of a service that implements
+     * a remote display provider service.
+     * </p>
+     *
+     * @return The IBinder instance associated with the provider.
+     */
+    public IBinder getBinder() {
+        return mStub;
+    }
+
+    /**
+     * Called when the current discovery mode changes.
+     *
+     * @param mode The new discovery mode.
+     */
+    public void onDiscoveryModeChanged(int mode) {
+    }
+
+    /**
+     * Called when the system would like to connect to a display.
+     *
+     * @param display The remote display.
+     */
+    public void onConnect(RemoteDisplay display) {
+    }
+
+    /**
+     * Called when the system would like to disconnect from a display.
+     *
+     * @param display The remote display.
+     */
+    public void onDisconnect(RemoteDisplay display) {
+    }
+
+    /**
+     * Called when the system would like to set the volume of a display.
+     *
+     * @param display The remote display.
+     * @param volume The desired volume.
+     */
+    public void onSetVolume(RemoteDisplay display, int volume) {
+    }
+
+    /**
+     * Called when the system would like to adjust the volume of a display.
+     *
+     * @param display The remote display.
+     * @param delta An increment to add to the current volume, such as +1 or -1.
+     */
+    public void onAdjustVolume(RemoteDisplay display, int delta) {
+    }
+
+    /**
+     * Gets the current discovery mode.
+     *
+     * @return The current discovery mode.
+     */
+    public int getDiscoveryMode() {
+        return mDiscoveryMode;
+    }
+
+    /**
+     * Gets the current collection of displays.
+     *
+     * @return The current collection of displays, which must not be modified.
+     */
+    public Collection<RemoteDisplay> getDisplays() {
+        return mDisplays.values();
+    }
+
+    /**
+     * Adds the specified remote display and notifies the system.
+     *
+     * @param display The remote display that was added.
+     * @throws IllegalStateException if there is already a display with the same id.
+     */
+    public void addDisplay(RemoteDisplay display) {
+        if (display == null || mDisplays.containsKey(display.getId())) {
+            throw new IllegalArgumentException("display");
+        }
+        mDisplays.put(display.getId(), display);
+        publishState();
+    }
+
+    /**
+     * Updates information about the specified remote display and notifies the system.
+     *
+     * @param display The remote display that was added.
+     * @throws IllegalStateException if the display was n
+     */
+    public void updateDisplay(RemoteDisplay display) {
+        if (display == null || mDisplays.get(display.getId()) != display) {
+            throw new IllegalArgumentException("display");
+        }
+        publishState();
+    }
+
+    /**
+     * Removes the specified remote display and tells the system about it.
+     *
+     * @param display The remote display that was removed.
+     */
+    public void removeDisplay(RemoteDisplay display) {
+        if (display == null || mDisplays.get(display.getId()) != display) {
+            throw new IllegalArgumentException("display");
+        }
+        mDisplays.remove(display.getId());
+        publishState();
+    }
+
+    /**
+     * Finds the remote display with the specified id, returns null if not found.
+     *
+     * @param id Id of the remote display.
+     * @return The display, or null if none.
+     */
+    public RemoteDisplay findRemoteDisplay(String id) {
+        return mDisplays.get(id);
+    }
+
+    /**
+     * Gets a pending intent to launch the remote display settings activity.
+     *
+     * @return A pending intent to launch the settings activity.
+     */
+    public PendingIntent getSettingsPendingIntent() {
+        if (mSettingsPendingIntent == null) {
+            Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+            settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            mSettingsPendingIntent = PendingIntent.getActivity(
+                    mContext, 0, settingsIntent, 0, null);
+        }
+        return mSettingsPendingIntent;
+    }
+
+    void setCallback(IRemoteDisplayCallback callback) {
+        mCallback = callback;
+        publishState();
+    }
+
+    void setDiscoveryMode(int mode) {
+        if (mDiscoveryMode != mode) {
+            mDiscoveryMode = mode;
+            onDiscoveryModeChanged(mode);
+        }
+    }
+
+    void publishState() {
+        if (mCallback != null) {
+            RemoteDisplayState state = new RemoteDisplayState();
+            final int count = mDisplays.size();
+            for (int i = 0; i < count; i++) {
+                final RemoteDisplay display = mDisplays.valueAt(i);
+                state.displays.add(display.getInfo());
+            }
+            try {
+                mCallback.onStateChanged(state);
+            } catch (RemoteException ex) {
+                // system server died?
+            }
+        }
+    }
+
+    final class ProviderStub extends IRemoteDisplayProvider.Stub {
+        @Override
+        public void setCallback(IRemoteDisplayCallback callback) {
+            mHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
+        }
+
+        @Override
+        public void setDiscoveryMode(int mode) {
+            mHandler.obtainMessage(MSG_SET_DISCOVERY_MODE, mode, 0).sendToTarget();
+        }
+
+        @Override
+        public void connect(String id) {
+            mHandler.obtainMessage(MSG_CONNECT, id).sendToTarget();
+        }
+
+        @Override
+        public void disconnect(String id) {
+            mHandler.obtainMessage(MSG_DISCONNECT, id).sendToTarget();
+        }
+
+        @Override
+        public void setVolume(String id, int volume) {
+            mHandler.obtainMessage(MSG_SET_VOLUME, volume, 0, id).sendToTarget();
+        }
+
+        @Override
+        public void adjustVolume(String id, int delta) {
+            mHandler.obtainMessage(MSG_ADJUST_VOLUME, delta, 0, id).sendToTarget();
+        }
+    }
+
+    final class ProviderHandler extends Handler {
+        public ProviderHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_CALLBACK: {
+                    setCallback((IRemoteDisplayCallback)msg.obj);
+                    break;
+                }
+                case MSG_SET_DISCOVERY_MODE: {
+                    setDiscoveryMode(msg.arg1);
+                    break;
+                }
+                case MSG_CONNECT: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onConnect(display);
+                    }
+                    break;
+                }
+                case MSG_DISCONNECT: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onDisconnect(display);
+                    }
+                    break;
+                }
+                case MSG_SET_VOLUME: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onSetVolume(display, msg.arg1);
+                    }
+                    break;
+                }
+                case MSG_ADJUST_VOLUME: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onAdjustVolume(display, msg.arg1);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
index 55d73f23..1cbc221 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -51,7 +51,7 @@
         mPosition = new int[count];
 
         cursor.moveToPosition(-1);
-        while (cursor.moveToNext()) {
+        while (cursor.moveToNext() && mCount < count) {
             final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
             final long lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
             if (rejectMimes != null && MimePredicate.mimeMatches(rejectMimes, mimeType)) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 3a8a3fb..34ce42d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -55,6 +55,10 @@
 public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
     private static final boolean LOGD = true;
 
+    // TODO: clean up cursor ownership so background thread doesn't traverse
+    // previously returned cursors for filtering/sorting; this currently races
+    // with the UI thread.
+
     private static final int MAX_OUTSTANDING_RECENTS = 4;
     private static final int MAX_OUTSTANDING_RECENTS_SVELTE = 2;
 
diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml
index 5169fef..edd6255 100644
--- a/packages/ExternalStorageProvider/AndroidManifest.xml
+++ b/packages/ExternalStorageProvider/AndroidManifest.xml
@@ -3,6 +3,7 @@
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/FusedLocation/res/values-ca/strings.xml b/packages/FusedLocation/res/values-ca/strings.xml
index bdd55dd..9dae512 100644
--- a/packages/FusedLocation/res/values-ca/strings.xml
+++ b/packages/FusedLocation/res/values-ca/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Ubicació unificada"</string>
+    <string name="app_label" msgid="5379477904423203699">"Ubicació combinada"</string>
 </resources>
diff --git a/packages/FusedLocation/res/values-de/strings.xml b/packages/FusedLocation/res/values-de/strings.xml
index 0d2cccc..d7e5faa 100644
--- a/packages/FusedLocation/res/values-de/strings.xml
+++ b/packages/FusedLocation/res/values-de/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Fused Location"</string>
+    <string name="app_label" msgid="5379477904423203699">"Kombinierte Standortbestimmung"</string>
 </resources>
diff --git a/packages/FusedLocation/res/values-pl/strings.xml b/packages/FusedLocation/res/values-pl/strings.xml
index b3a9e2a..4637034 100644
--- a/packages/FusedLocation/res/values-pl/strings.xml
+++ b/packages/FusedLocation/res/values-pl/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Przybliżona lokalizacja"</string>
+    <string name="app_label" msgid="5379477904423203699">"Uśredniona lokalizacja"</string>
 </resources>
diff --git a/packages/FusedLocation/res/values-pt/strings.xml b/packages/FusedLocation/res/values-pt/strings.xml
index cf5f5bf..4f8277a 100644
--- a/packages/FusedLocation/res/values-pt/strings.xml
+++ b/packages/FusedLocation/res/values-pt/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Localização fundida"</string>
+    <string name="app_label" msgid="5379477904423203699">"Localização combinada"</string>
 </resources>
diff --git a/packages/Keyguard/AndroidManifest.xml b/packages/Keyguard/AndroidManifest.xml
index 9e296e2..66d1e75 100644
--- a/packages/Keyguard/AndroidManifest.xml
+++ b/packages/Keyguard/AndroidManifest.xml
@@ -38,6 +38,7 @@
     <uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
+    <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
 
     <application android:label="@string/app_name"
         android:process="com.android.systemui"
diff --git a/packages/Keyguard/res/layout/keyguard_presentation.xml b/packages/Keyguard/res/layout/keyguard_presentation.xml
new file mode 100644
index 0000000..7df0b70
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_presentation.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2013, 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 a view that shows general status information in Keyguard. -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/presentation"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.keyguard.KeyguardStatusView
+        android:id="@+id/clock"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="@string/keyguard_accessibility_status">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal|top"
+            android:orientation="vertical"
+            android:focusable="true">
+            <TextClock
+                android:id="@+id/clock_view"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal|top"
+                android:textColor="@color/clock_white"
+                android:singleLine="true"
+                style="@style/widget_big_thin"
+                android:format12Hour="@string/keyguard_widget_12_hours_format"
+                android:format24Hour="@string/keyguard_widget_24_hours_format"
+                android:baselineAligned="true"
+                android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
+
+            <include layout="@layout/keyguard_status_area" />
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dip"
+                android:layout_gravity="center_horizontal"
+                android:src="@drawable/kg_security_lock_normal" />
+        </LinearLayout>
+    </com.android.keyguard.KeyguardStatusView>
+
+</FrameLayout>
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 5857fc2..a4d298a 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -26,7 +26,7 @@
     android:layout_height="match_parent"
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal">
+    android:gravity="center">
 
     <com.android.keyguard.KeyguardStatusView
         android:id="@+id/keyguard_status_view_face_palm"
diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
index 3dc4d5c..74e6f33 100644
--- a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
+++ b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Color;
-import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
@@ -41,7 +40,7 @@
     private static final String TAG = CameraWidgetFrame.class.getSimpleName();
     private static final boolean DEBUG = KeyguardHostView.DEBUG;
     private static final int WIDGET_ANIMATION_DURATION = 250; // ms
-    private static final int WIDGET_WAIT_DURATION = 650; // ms
+    private static final int WIDGET_WAIT_DURATION = 400; // ms
     private static final int RECOVERY_DELAY = 1000; // ms
 
     interface Callbacks {
@@ -68,6 +67,7 @@
     private FixedSizeFrameLayout mPreview;
     private View mFullscreenPreview;
     private View mFakeNavBar;
+    private boolean mUseFastTransition;
 
     private final Runnable mTransitionToCameraRunnable = new Runnable() {
         @Override
@@ -418,7 +418,8 @@
     private void rescheduleTransitionToCamera() {
         if (DEBUG) Log.d(TAG, "rescheduleTransitionToCamera at " + SystemClock.uptimeMillis());
         mHandler.removeCallbacks(mTransitionToCameraRunnable);
-        mHandler.postDelayed(mTransitionToCameraRunnable, WIDGET_WAIT_DURATION);
+        final long duration = mUseFastTransition ? 0 : WIDGET_WAIT_DURATION;
+        mHandler.postDelayed(mTransitionToCameraRunnable, duration);
     }
 
     private void cancelTransitionToCamera() {
@@ -513,4 +514,8 @@
         if (DEBUG) Log.d(TAG, "setInsets: " + insets);
         mInsets.set(insets);
     }
+
+    public void setUseFastTransition(boolean useFastTransition) {
+        mUseFastTransition = useFastTransition;
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
new file mode 100644
index 0000000..6bcbd6c
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2013 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.android.keyguard;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.graphics.Point;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.util.Slog;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+
+public class KeyguardDisplayManager {
+    protected static final String TAG = "KeyguardDisplayManager";
+    private static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    Presentation mPresentation;
+    private MediaRouter mMediaRouter;
+    private Context mContext;
+    private boolean mShowing;
+
+    KeyguardDisplayManager(Context context) {
+        mContext = context;
+        mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+    }
+
+    void show() {
+        if (!mShowing) {
+            if (DEBUG) Slog.v(TAG, "show");
+            mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                    mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+            updateDisplays(true);
+        }
+        mShowing = true;
+    }
+
+    void hide() {
+        if (mShowing) {
+            if (DEBUG) Slog.v(TAG, "hide");
+            mMediaRouter.removeCallback(mMediaRouterCallback);
+            updateDisplays(false);
+        }
+        mShowing = false;
+    }
+
+    private final MediaRouter.SimpleCallback mMediaRouterCallback =
+            new MediaRouter.SimpleCallback() {
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+            if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
+            updateDisplays(mShowing);
+        }
+
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+            if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
+            updateDisplays(mShowing);
+        }
+
+        @Override
+        public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
+            if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
+            updateDisplays(mShowing);
+        }
+    };
+
+    private OnDismissListener mOnDismissListener = new OnDismissListener() {
+
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            mPresentation = null;
+        }
+    };
+
+    protected void updateDisplays(boolean showing) {
+        if (showing) {
+            MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
+                    MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+            boolean useDisplay = route != null
+                    && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+            Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;
+
+            if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
+                if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+
+            if (mPresentation == null && presentationDisplay != null) {
+                if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);
+                mPresentation = new KeyguardPresentation(mContext, presentationDisplay);
+                mPresentation.setOnDismissListener(mOnDismissListener);
+                try {
+                    mPresentation.show();
+                } catch (WindowManager.InvalidDisplayException ex) {
+                    Slog.w(TAG, "Invalid display:", ex);
+                    mPresentation = null;
+                }
+            }
+        } else {
+            if (mPresentation != null) {
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+        }
+    }
+
+    private final static class KeyguardPresentation extends Presentation {
+        private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
+        private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
+        private View mClock;
+        private int mUsableWidth;
+        private int mUsableHeight;
+        private int mMarginTop;
+        private int mMarginLeft;
+        Runnable mMoveTextRunnable = new Runnable() {
+            @Override
+            public void run() {
+                int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
+                int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
+                mClock.setTranslationX(x);
+                mClock.setTranslationY(y);
+                mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
+            }
+        };
+
+        public KeyguardPresentation(Context context, Display display) {
+            super(context, display);
+            getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        }
+
+        public void onDetachedFromWindow() {
+            mClock.removeCallbacks(mMoveTextRunnable);
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            Point p = new Point();
+            getDisplay().getSize(p);
+            mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
+            mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
+            mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
+            mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
+
+            setContentView(R.layout.keyguard_presentation);
+            mClock = findViewById(R.id.clock);
+
+            // Avoid screen burn in
+            mClock.post(mMoveTextRunnable);
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
index 2719c5c..349078f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
@@ -60,12 +60,12 @@
  */
 public class KeyguardTransportControlView extends FrameLayout {
 
-    private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
     private static final int RESET_TO_METADATA_DELAY = 5000;
     protected static final boolean DEBUG = false;
     protected static final String TAG = "TransportControlView";
 
     private static final boolean ANIMATE_TRANSITIONS = true;
+    protected static final long QUIESCENT_PLAYBACK_FACTOR = 1000;
 
     private ViewGroup mMetadataContainer;
     private ViewGroup mInfoContainer;
@@ -89,11 +89,9 @@
     private ImageView mBadge;
 
     private boolean mSeekEnabled;
-    private boolean mUserSeeking;
     private java.text.DateFormat mFormat;
 
-    private Date mTimeElapsed;
-    private Date mTrackDuration;
+    private Date mTempDate = new Date();
 
     /**
      * The metadata which should be populated into the view once we've been attached
@@ -111,18 +109,25 @@
 
         @Override
         public void onClientPlaybackStateUpdate(int state) {
-            setSeekBarsEnabled(false);
             updatePlayPauseState(state);
         }
 
         @Override
         public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
                 long currentPosMs, float speed) {
-            setSeekBarsEnabled(mMetadata != null && mMetadata.duration > 0);
             updatePlayPauseState(state);
             if (DEBUG) Log.d(TAG, "onClientPlaybackStateUpdate(state=" + state +
                     ", stateChangeTimeMs=" + stateChangeTimeMs + ", currentPosMs=" + currentPosMs +
                     ", speed=" + speed + ")");
+
+            removeCallbacks(mUpdateSeekBars);
+            // Since the music client may be responding to historical events that cause the
+            // playback state to change dramatically, wait until things become quiescent before
+            // resuming automatic scrub position update.
+            if (mTransientSeek.getVisibility() == View.VISIBLE
+                    && playbackPositionShouldMove(mCurrentPlayState)) {
+                postDelayed(mUpdateSeekBars, QUIESCENT_PLAYBACK_FACTOR);
+            }
         }
 
         @Override
@@ -136,15 +141,21 @@
         }
     };
 
-    private final Runnable mUpdateSeekBars = new Runnable() {
+    private class UpdateSeekBarRunnable implements  Runnable {
         public void run() {
-            if (updateSeekBars()) {
+            boolean seekAble = updateOnce();
+            if (seekAble) {
                 removeCallbacks(this);
                 postDelayed(this, 1000);
             }
         }
+        public boolean updateOnce() {
+            return updateSeekBars();
+        }
     };
 
+    private final UpdateSeekBarRunnable mUpdateSeekBars = new UpdateSeekBarRunnable();
+
     private final Runnable mResetToMetadata = new Runnable() {
         public void run() {
             resetToMetadata();
@@ -163,6 +174,7 @@
             }
             if (keyCode != -1) {
                 sendMediaButtonClick(keyCode);
+                delayResetToMetadata(); // if the scrub bar is showing, keep showing it.
             }
         }
     };
@@ -177,25 +189,67 @@
         }
     };
 
+    // This class is here to throttle scrub position updates to the music client
+    class FutureSeekRunnable implements Runnable {
+        private int mProgress;
+        private boolean mPending;
+
+        public void run() {
+            scrubTo(mProgress);
+            mPending = false;
+        }
+
+        void setProgress(int progress) {
+            mProgress = progress;
+            if (!mPending) {
+                mPending = true;
+                postDelayed(this, 30);
+            }
+        }
+    };
+
+    // This is here because RemoteControlClient's method isn't visible :/
+    private final static boolean playbackPositionShouldMove(int playstate) {
+        switch(playstate) {
+            case RemoteControlClient.PLAYSTATE_STOPPED:
+            case RemoteControlClient.PLAYSTATE_PAUSED:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+            case RemoteControlClient.PLAYSTATE_ERROR:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                return false;
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            default:
+                return true;
+        }
+    }
+
+    private final FutureSeekRunnable mFutureSeekRunnable = new FutureSeekRunnable();
+
     private final SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener =
             new SeekBar.OnSeekBarChangeListener() {
         @Override
         public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
             if (fromUser) {
-                scrubTo(progress);
+                mFutureSeekRunnable.setProgress(progress);
                 delayResetToMetadata();
+                mTempDate.setTime(progress);
+                mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
+            } else {
+                updateSeekDisplay();
             }
-            updateSeekDisplay();
         }
 
         @Override
         public void onStartTrackingTouch(SeekBar seekBar) {
-            mUserSeeking = true;
+            delayResetToMetadata();
+            removeCallbacks(mUpdateSeekBars); // don't update during user interaction
         }
 
         @Override
         public void onStopTrackingTouch(SeekBar seekBar) {
-            mUserSeeking = false;
         }
     };
 
@@ -247,17 +301,11 @@
         if (enabled == mSeekEnabled) return;
 
         mSeekEnabled = enabled;
-        if (mTransientSeek.getVisibility() == VISIBLE) {
+        if (mTransientSeek.getVisibility() == VISIBLE && !enabled) {
             mTransientSeek.setVisibility(INVISIBLE);
             mMetadataContainer.setVisibility(VISIBLE);
-            mUserSeeking = false;
             cancelResetToMetadata();
         }
-        if (enabled) {
-            mUpdateSeekBars.run();
-        } else {
-            removeCallbacks(mUpdateSeekBars);
-        }
     }
 
     public void setTransportControlCallback(KeyguardHostView.TransportControlCallback
@@ -294,6 +342,8 @@
         }
         final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
         setEnableMarquee(screenOn);
+        // Allow long-press anywhere else in this view to show the seek bar
+        setOnLongClickListener(mTransportShowSeekBarListener);
     }
 
     @Override
@@ -326,7 +376,6 @@
         mAudioManager.unregisterRemoteController(mRemoteController);
         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitor);
         mMetadata.clear();
-        mUserSeeking = false;
         removeCallbacks(mUpdateSeekBars);
     }
 
@@ -484,18 +533,12 @@
 
     void updateSeekDisplay() {
         if (mMetadata != null && mRemoteController != null && mFormat != null) {
-            if (mTimeElapsed == null) {
-                mTimeElapsed = new Date();
-            }
-            if (mTrackDuration == null) {
-                mTrackDuration = new Date();
-            }
-            mTimeElapsed.setTime(mRemoteController.getEstimatedMediaPosition());
-            mTrackDuration.setTime(mMetadata.duration);
-            mTransientSeekTimeElapsed.setText(mFormat.format(mTimeElapsed));
-            mTransientSeekTimeTotal.setText(mFormat.format(mTrackDuration));
+            mTempDate.setTime(mRemoteController.getEstimatedMediaPosition());
+            mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
+            mTempDate.setTime(mMetadata.duration);
+            mTransientSeekTimeTotal.setText(mFormat.format(mTempDate));
 
-            if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTimeElapsed +
+            if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTempDate +
                     " duration=" + mMetadata.duration);
         }
     }
@@ -508,10 +551,16 @@
             mTransientSeek.setVisibility(INVISIBLE);
             mMetadataContainer.setVisibility(VISIBLE);
             cancelResetToMetadata();
+            removeCallbacks(mUpdateSeekBars); // don't update if scrubber isn't visible
         } else {
             mTransientSeek.setVisibility(VISIBLE);
             mMetadataContainer.setVisibility(INVISIBLE);
             delayResetToMetadata();
+            if (playbackPositionShouldMove(mCurrentPlayState)) {
+                mUpdateSeekBars.run();
+            } else {
+                mUpdateSeekBars.updateOnce();
+            }
         }
         mTransportControlCallback.userActivity();
         return true;
@@ -573,9 +622,6 @@
             case RemoteControlClient.PLAYSTATE_PLAYING:
                 imageResId = R.drawable.ic_media_pause;
                 imageDescId = R.string.keyguard_transport_pause_description;
-                if (mSeekEnabled) {
-                    mUpdateSeekBars.run();
-                }
                 break;
 
             case RemoteControlClient.PLAYSTATE_BUFFERING:
@@ -590,10 +636,9 @@
                 break;
         }
 
-        if (state != RemoteControlClient.PLAYSTATE_PLAYING) {
-            removeCallbacks(mUpdateSeekBars);
-            updateSeekBars();
-        }
+        boolean clientSupportsSeek = mMetadata != null && mMetadata.duration > 0;
+        setSeekBarsEnabled(clientSupportsSeek);
+
         mBtnPlay.setImageResource(imageResId);
         mBtnPlay.setContentDescription(getResources().getString(imageDescId));
         mCurrentPlayState = state;
@@ -601,11 +646,9 @@
 
     boolean updateSeekBars() {
         final int position = (int) mRemoteController.getEstimatedMediaPosition();
+        if (DEBUG) Log.v(TAG, "Estimated time:" + position);
         if (position >= 0) {
-            if (DEBUG) Log.v(TAG, "Seek to " + position);
-            if (!mUserSeeking) {
-                mTransientSeekBar.setProgress(position);
-            }
+            mTransientSeekBar.setProgress(position);
             return true;
         }
         Log.w(TAG, "Updating seek bars; received invalid estimated media position (" +
@@ -671,34 +714,4 @@
     public boolean providesClock() {
         return false;
     }
-
-    private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
-        switch (state) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                // actively playing or about to play
-                return true;
-            case RemoteControlClient.PLAYSTATE_NONE:
-                return false;
-            case RemoteControlClient.PLAYSTATE_STOPPED:
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                // we have stopped playing, check how long ago
-                if (DEBUG) {
-                    if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
-                        Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
-                    } else {
-                        Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
-                    }
-                }
-                return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
-            default:
-                Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
-                return false;
-        }
-    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index fd7cae6..6aa0a4b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -61,9 +61,11 @@
 public class KeyguardViewManager {
     private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
     private static String TAG = "KeyguardViewManager";
-    public static boolean USE_UPPER_CASE = true;
     public final static String IS_SWITCHING_USER = "is_switching_user";
 
+    // Delay dismissing keyguard to allow animations to complete.
+    private static final int HIDE_KEYGUARD_DELAY = 500;
+
     // Timeout used for keypresses
     static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
 
@@ -509,9 +511,10 @@
                             mKeyguardHost.setCustomBackground(null);
                             updateShowWallpaper(true);
                             mKeyguardHost.removeView(lastView);
+                            mViewMediatorCallback.keyguardGone();
                         }
                     }
-                }, 500);
+                }, HIDE_KEYGUARD_DELAY);
             }
         }
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index b92ae90..4086f84 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -200,7 +200,7 @@
 
     // cached value of whether we are showing (need to know this to quickly
     // answer whether the input should be restricted)
-    private boolean mShowing = false;
+    private boolean mShowing;
 
     // true if the keyguard is hidden by another window
     private boolean mHidden = false;
@@ -253,6 +253,11 @@
     private final float mLockSoundVolume;
 
     /**
+     * For managing external displays
+     */
+    private KeyguardDisplayManager mKeyguardDisplayManager;
+
+    /**
      * Cache of avatar drawables, for use by KeyguardMultiUserAvatar.
      */
     private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache();
@@ -304,6 +309,11 @@
          * Report that the keyguard is dismissable, pending the next keyguardDone call.
          */
         void keyguardDonePending();
+
+        /**
+         * Report when keyguard is actually gone
+         */
+        void keyguardGone();
     }
 
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -457,6 +467,11 @@
         public void keyguardDonePending() {
             mKeyguardDonePending = true;
         }
+
+        @Override
+        public void keyguardGone() {
+            mKeyguardDisplayManager.hide();
+        }
     };
 
     private void userActivity() {
@@ -483,6 +498,8 @@
 
         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
 
+        mKeyguardDisplayManager = new KeyguardDisplayManager(context);
+
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
 
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
@@ -491,6 +508,10 @@
                 ? lockPatternUtils : new LockPatternUtils(mContext);
         mLockPatternUtils.setCurrentUser(UserHandle.USER_OWNER);
 
+        // Assume keyguard is showing (unless it's disabled) until we know for sure...
+        mShowing = (mUpdateMonitor.isDeviceProvisioned() || mLockPatternUtils.isSecure())
+                && !mLockPatternUtils.isLockScreenDisabled();
+
         WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
 
         mKeyguardViewManager = new KeyguardViewManager(context, wm, mViewMediatorCallback,
@@ -1218,6 +1239,7 @@
 
             mShowKeyguardWakeLock.release();
         }
+        mKeyguardDisplayManager.show();
     }
 
     /**
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
index f0413d6..169899f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -154,6 +154,10 @@
     public void onPageSwitching(View newPage, int newPageIndex) {
         if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
             boolean isCameraPage = newPage instanceof CameraWidgetFrame;
+            if (isCameraPage) {
+                CameraWidgetFrame camera = (CameraWidgetFrame) newPage;
+                camera.setUseFastTransition(mKeyguardWidgetPager.isWarping());
+            }
             SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
             scl.setChallengeInteractive(!isCameraPage);
             final int currentFlags = mKeyguardWidgetPager.getSystemUiVisibility();
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
index b9404d4..53c17a5 100644
--- a/packages/Keyguard/src/com/android/keyguard/PagedView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PagedView.java
@@ -82,13 +82,13 @@
 
     private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
     // The page is moved more than halfway, automatically move to the next page on touch up.
-    private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
+    private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.5f;
 
     // The following constants need to be scaled based on density. The scaled versions will be
     // assigned to the corresponding member variables below.
-    private static final int FLING_THRESHOLD_VELOCITY = 500;
+    private static final int FLING_THRESHOLD_VELOCITY = 1500;
     private static final int MIN_SNAP_VELOCITY = 1500;
-    private static final int MIN_FLING_VELOCITY = 250;
+    private static final int MIN_FLING_VELOCITY = 500;
 
     // We are disabling touch interaction of the widget region for factory ROM.
     private static final boolean DISABLE_TOUCH_INTERACTION = false;
@@ -1938,10 +1938,12 @@
 
         if (isWarping()) {
             dispatchOnPageEndWarp();
+            notifyPageSwitching(whichPage);
             resetPageWarp();
+        } else {
+            notifyPageSwitching(whichPage);
         }
 
-        notifyPageSwitching(whichPage);
         View focusedChild = getFocusedChild();
         if (focusedChild != null && whichPage != mCurrentPage &&
                 focusedChild == getPageAt(mCurrentPage)) {
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
index f573d9d..d9f0a9a 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_error.xml
@@ -35,7 +35,6 @@
             android:layout_marginBottom="32dip"
             android:layout_gravity="center"
             style="?android:attr/buttonBarButtonStyle"
-            android:singleLine="true"
             android:ellipsize="end"
             android:text="@string/print_error_default_message"
             android:textColor="@color/important_text"
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index b8287ae..a10a5a0 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Soekkassie vertoon"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Soekkassie weggesteek"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Voeg drukker by"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Kies drukker"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Vergeet drukker"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> drukker gekry"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> drukkers gekry"</item>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index d73cdd9..3b94d6d 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"የፍለጋ ሳጥን ይታያል"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"የፍለጋ ሳጥን ተደብቋል"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"አታሚ አክል"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"አታሚ ምረጥ"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"አታሚ እርሳ"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚ ተገኝቷል"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚዎች ተገኝተዋል"</item>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 14b6467..b883f93 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -23,7 +23,7 @@
     <string name="label_destination" msgid="9132510997381599275">"الوجهة"</string>
     <string name="label_copies" msgid="3634531042822968308">"عدد النسخ"</string>
     <string name="label_paper_size" msgid="8681895607876809323">"حجم الورق"</string>
-    <string name="label_color" msgid="1108690305218188969">"اللون"</string>
+    <string name="label_color" msgid="1108690305218188969">"ألوان"</string>
     <string name="label_orientation" msgid="2853142581990496477">"الاتجاه"</string>
     <string name="label_pages" msgid="6300874667546617333">"الصفحات (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"على سبيل المثال، 1—5،8،11—13"</string>
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"تم إظهار مربع البحث"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"تم إخفاء مربع البحث"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"إضافة طابعة"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"حدد الطابعة"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"تجاهل الطابعة"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> طابعة"</item>
     <item quantity="other" msgid="6533817036607128241">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> من الطابعات"</item>
@@ -64,11 +66,11 @@
     <string name="print_error_default_message" msgid="8568506918983980567">"تعذر إنشاء عملية الطباعة"</string>
   <string-array name="color_mode_labels">
     <item msgid="7602948745415174937">"أبيض وأسود"</item>
-    <item msgid="2762241247228983754">"اللون"</item>
+    <item msgid="2762241247228983754">"ملونة"</item>
   </string-array>
   <string-array name="orientation_labels">
     <item msgid="4061931020926489228">"عمودي"</item>
-    <item msgid="3199660090246166812">"أفقية"</item>
+    <item msgid="3199660090246166812">"أفقي"</item>
   </string-array>
   <string-array name="page_options_labels">
     <item msgid="7421377442011699994">"الكل"</item>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 47f86c6..4009aa2 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Полето за търсене е показано"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Полето за търсене е скрито"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Добавяне на принтер"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Избиране на принтер"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Забравяне на принтера"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Намерен е <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
     <item quantity="other" msgid="6533817036607128241">"Намерени са <xliff:g id="COUNT">%1$s</xliff:g> принтера"</item>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index fc60b0a..a429dd5 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Es mostra el quadre de cerca"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"S\'ha amagat el quadre de cerca"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Afegeix una impressora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Selecciona una impressora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Oblida la impressora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"S\'ha trobat <xliff:g id="COUNT">%1$s</xliff:g> impressora"</item>
     <item quantity="other" msgid="6533817036607128241">"S\'han trobat <xliff:g id="COUNT">%1$s</xliff:g> impressores"</item>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 3f806d6..3ddc701 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Vyhledávací pole se zobrazuje"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Vyhledávací pole je skryto"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Přidat tiskárnu"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Vybrat tiskárnu"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Odstranit tiskárnu"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 60c22bb..74190b4 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Søgefeltet vises"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Søgefeltet er skjult"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Tilføj printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Vælg printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Glem printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
     <item quantity="other" msgid="6533817036607128241">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printere"</item>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index 54c936f..6b83ac3 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Suchfeld angezeigt"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Suchfeld ausgeblendet"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Drucker hinzufügen"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Drucker auswählen"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Drucker wieder vergessen"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 168f87b..795e730 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Εμφάνιση πλαισίου αναζήτησης"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Απόκρυψη πλαισίου αναζήτησης"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Προσθήκη εκτυπωτή"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Επιλογή εκτυπωτή"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Διαγραφή εκτυπωτή"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Βρέθηκε <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτής"</item>
     <item quantity="other" msgid="6533817036607128241">"Βρέθηκαν <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτές"</item>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index 98c3688..27372f8 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Search box shown"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Search box hidden"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index 98c3688..27372f8 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Search box shown"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Search box hidden"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index bfdf933..c7d12af 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Cuadro de búsqueda visible"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Cuadro de búsqueda oculto"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Agregar impresora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"No recordar impresora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Se encontró <xliff:g id="COUNT">%1$s</xliff:g> impresora."</item>
     <item quantity="other" msgid="6533817036607128241">"Se encontraron <xliff:g id="COUNT">%1$s</xliff:g> impresoras."</item>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 28df5f0..0225cad 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Cuadro de búsqueda visible"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Cuadro de búsqueda oculto"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Añadir impresora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Borrar impresora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Se ha encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresora"</item>
     <item quantity="other" msgid="6533817036607128241">"Se han encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresoras"</item>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 1114f9f..2b3b352 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Otsingukast on kuvatud"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Otsingukast on peidetud"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Lisa printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Printeri valimine"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Printeri unustamine"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
     <item quantity="other" msgid="6533817036607128241">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printerit"</item>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 950ef92..49bae323 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"کادر جستجو نمایان شد"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"کادر جستجو پنهان شد"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"افزودن چاپگر"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"انتخاب چاپگر"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"فراموش کردن چاپگر"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index 239afcf..8658e04 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Hakukenttä näkyvissä"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Hakukenttä piilotettu"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Lisää tulostin"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Valitse tulostin"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Unohda tulostin"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostin"</item>
     <item quantity="other" msgid="6533817036607128241">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostinta"</item>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 3880745..9a3352c 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Champ de recherche affiché"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Champ de recherche masqué"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Sélectionner une imprimante"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées"</item>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 961d344..cfb557e 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Champ de recherche affiché."</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Champ de recherche masqué."</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Sélectionner une imprimante"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Supprimer l\'imprimante"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée."</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées."</item>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 4d1ddd8..60406b7 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"खोज बॉक्स प्रदर्शित है"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"खोज बॉक्स छिपा हुआ है"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"प्रिंटर जोड़ें"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"प्रिंटर चुनें"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"प्रिंटर को भूल जाएं"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिला"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिले"</item>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 50b56ff..7182cf6 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Okvir za pretraživanje prikazan je"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Okvir za pretraživanje skriven je"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Dodaj pisač"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Odaberite pisač"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Zaboravite pisač"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Pronađen je <xliff:g id="COUNT">%1$s</xliff:g> pisač"</item>
     <item quantity="other" msgid="6533817036607128241">"Pronađen je sljedeći broj pisača: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 79912fc..6a0741b 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Keresőmező megjelenítve"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Keresőmező elrejtve"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Nyomtató hozzáadása"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Nyomtató kiválasztása"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Nyomtató elfelejtése"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 7d95f7b..1423b82 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Որոնման վանդակը ցուցադրված է"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Որոնման վանդակը թաքցվել է"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ավելացնել տպիչ"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Ընտրել տպիչ"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Մոռանալ տպիչը"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 1206676..2b80d07 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kotak telusur ditampilkan"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kotak telusur disembunyikan"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Tambahkan printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Pilih printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Lupakan printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 4223188..96c3b48 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Casella di ricerca visualizzata"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Casella di ricerca nascosta"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Aggiungi stampante"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> stampante trovata"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> stampanti trovate"</item>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 2a9e0df..3e0e732 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"תיבת החיפוש מוצגת"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"תיבת החיפוש מוסתרת"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"הוסף מדפסת"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"בחר מדפסת"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"שכח את המדפסת"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"נמצאה מדפסת <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"נמצאו <xliff:g id="COUNT">%1$s</xliff:g> מדפסות"</item>
diff --git a/packages/PrintSpooler/res/values-ja/arrays.xml b/packages/PrintSpooler/res/values-ja/arrays.xml
index 57088c8..460bdb2 100644
--- a/packages/PrintSpooler/res/values-ja/arrays.xml
+++ b/packages/PrintSpooler/res/values-ja/arrays.xml
@@ -20,13 +20,13 @@
         <item>JIS_B9</item>
         <item>JIS_B8</item>
         <item>JIS_B7</item>
-        <item>JIS_b6</item>
-        <item>JIS_b5</item>
-        <item>JIS_b4</item>
-        <item>JIS_b3</item>
-        <item>JIS_b2</item>
-        <item>JIS_b1</item>
-        <item>JIS_b0</item>
+        <item>JIS_B6</item>
+        <item>JIS_B5</item>
+        <item>JIS_B4</item>
+        <item>JIS_B3</item>
+        <item>JIS_B2</item>
+        <item>JIS_B1</item>
+        <item>JIS_B0</item>
         <item>JIS_EXEC</item>
         <item>JPN_CHOU4</item>
         <item>JPN_CHOU3</item>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index e6ae97a..94e8441 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"検索ボックスは表示されています"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"検索ボックスは表示されていません"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"プリンタを追加"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"プリンタを選択"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"プリンタを切断"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 3fc1f3a..d36b7c9 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"საძიებო ველი ნაჩვენებია"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"საძიებო ველი დამალულია"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"პრინტერის დამატება"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"პრინტერის არჩევა"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"პრინტერის დავიწყება"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
     <item quantity="other" msgid="6533817036607128241">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 8ed85273..c89f9bf 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"បាន​បង្ហាញ​ប្រ​អប់​ស្វែងរក"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"បាន​លាក់​ប្រអប់​ស្វែងរក"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"បន្ថែម​ម៉ាស៊ីន​បោះពុម្ព"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"ជ្រើស​ម៉ាស៊ីន​បោះពុម្ព"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"ភ្លេច​​ម៉ាស៊ីន​បោះពុម្ព"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"រក​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"រក​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 83155fd..3b2fef7 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"검색창 표시됨"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"검색창 숨겨짐"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"프린터 추가"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"프린터 선택"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"프린터 삭제"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
     <item quantity="other" msgid="6533817036607128241">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 45bb9bc..f954606 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ກ່ອງຊອກຫາຖືກສະແດງ"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ກ່ອງຊອກຫາຖືກເຊື່ອງ"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"ເພີ່ມເຄື່ອງພິມ"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"ເລືອກເຄື່ອງພິມ"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"ລືມເຄື່ອງພິມ"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
     <item quantity="other" msgid="6533817036607128241">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 1560dce..0c4e386 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Paieškos laukelis rodomas"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Paieškos laukelis paslėptas"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Pridėti spausdintuvą"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Pasirinkti spausdintuvą"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Pamiršti spausdintuvą"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 3a6049c..3fffdfe 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Meklēšanas lodziņš ir redzams."</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Meklēšanas lodziņš ir paslēpts."</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Pievienot printeri"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Atlasīt printeri"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Neatcerēties printeri"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Atrasts <xliff:g id="COUNT">%1$s</xliff:g> printeris"</item>
     <item quantity="other" msgid="6533817036607128241">"Atrasti <xliff:g id="COUNT">%1$s</xliff:g> printeri"</item>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 8062eb1..e429387 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Хайлтын нүдийг гаргах"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Хайлтын нүдийг далдлах"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Принтер нэмэх"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Принтер сонгох"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Принтерийг мартах"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index d113749..cca5d2c 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kotak carian ditunjukkan"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kotak carian tersembunyi"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Tambah pencetak"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Pilih pencetak"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Lupakan pencetak"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index abed60d..f6a60c6 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Søkefeltet vises"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Søkefeltet er skjult"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Legg til skriver"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Velg skriver"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Glem skriveren"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skriver ble funnet"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivere ble funnet"</item>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 3289d12..dc12508 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Zoekvak weergegeven"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Zoekvak verborgen"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Printer toevoegen"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Printer selecteren"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Printer vergeten"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer gevonden"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers gevonden"</item>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 10cb2e7..81acc76 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Pole wyszukiwania jest widoczne"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Pole wyszukiwania jest ukryte"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Dodaj drukarkę"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Wybierz drukarkę"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Nie zapamiętuj drukarki"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Znaleziono <xliff:g id="COUNT">%1$s</xliff:g> drukarkę"</item>
     <item quantity="other" msgid="6533817036607128241">"Znalezione drukarki: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 630fe03..6bfc395 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caixa de pesquisa apresentada"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caixa de pesquisa ocultada"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 6e5eab1..82c157d 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caixa de pesquisa exibida"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caixa de pesquisa oculta"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index c4d9f8e..79c3bdc 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caseta de căutare este afișată"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caseta de căutare este ascunsă"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Adăugați o imprimantă"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Selectați imprimanta"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Omiteți imprimanta"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantă găsită"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (de) imprimante găsite"</item>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index b1335a0..a27f3c8 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -22,8 +22,8 @@
     <string name="save_button" msgid="1921310454071758999">"Сохранить"</string>
     <string name="label_destination" msgid="9132510997381599275">"Принтер"</string>
     <string name="label_copies" msgid="3634531042822968308">"Копии"</string>
-    <string name="label_paper_size" msgid="8681895607876809323">"Размер бумаги"</string>
-    <string name="label_color" msgid="1108690305218188969">"Цветной"</string>
+    <string name="label_paper_size" msgid="8681895607876809323">"Формат"</string>
+    <string name="label_color" msgid="1108690305218188969">"Печать"</string>
     <string name="label_orientation" msgid="2853142581990496477">"Ориентация"</string>
     <string name="label_pages" msgid="6300874667546617333">"СТРАНИЦЫ (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"напр., 1–5, 8, 11–13"</string>
@@ -32,7 +32,7 @@
     <string name="printing_app_crashed" msgid="854477616686566398">"Сбой приложения печати"</string>
     <string name="page_count_unknown" msgid="6058852665954511124">"Количество страниц"</string>
     <string name="generating_print_job" msgid="3119608742651698916">"Создание задания печати…"</string>
-    <string name="save_as_pdf" msgid="5718454119847596853">"Сохранить как PDF-файл"</string>
+    <string name="save_as_pdf" msgid="5718454119847596853">"Сохранить как PDF"</string>
     <string name="all_printers" msgid="5018829726861876202">"Все принтеры"</string>
     <string name="print_dialog" msgid="32628687461331979">"Диалоговое окно печати"</string>
     <string name="search" msgid="5421724265322228497">"Поиск"</string>
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Окно поиска показано"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Окно поиска скрыто"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Добавить принтер"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Выбрать принтер"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Удалить принтер"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Найден <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
     <item quantity="other" msgid="6533817036607128241">"Найдено принтеров: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
@@ -63,12 +65,12 @@
     <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – недоступен"</string>
     <string name="print_error_default_message" msgid="8568506918983980567">"Не удалось отправить документ на печать."</string>
   <string-array name="color_mode_labels">
-    <item msgid="7602948745415174937">"Черно-белое"</item>
-    <item msgid="2762241247228983754">"Цветное"</item>
+    <item msgid="7602948745415174937">"Черно-белая"</item>
+    <item msgid="2762241247228983754">"Цветная"</item>
   </string-array>
   <string-array name="orientation_labels">
-    <item msgid="4061931020926489228">"Книжная"</item>
-    <item msgid="3199660090246166812">"Альбомная"</item>
+    <item msgid="4061931020926489228">"Книга"</item>
+    <item msgid="3199660090246166812">"Альбом"</item>
   </string-array>
   <string-array name="page_options_labels">
     <item msgid="7421377442011699994">"Все"</item>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 922a759..39a022d 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Vyhľadávacie pole sa zobrazuje"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Vyhľadávacie pole je skryté"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Pridať tlačiareň"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Vybrať tlačiareň"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Odstrániť tlačiareň"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Našla sa <xliff:g id="COUNT">%1$s</xliff:g> tlačiareň"</item>
     <item quantity="other" msgid="6533817036607128241">"Počet nájdených tlačiarní: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index abd07c6..5d4fe94 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Iskalno polje je prikazano"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Iskalno polje je skrito"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Dodajanje tiskalnika"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Izbira tiskalnika"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Odstranitev tiskalnika"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Najden <xliff:g id="COUNT">%1$s</xliff:g> tiskalnik"</item>
     <item quantity="other" msgid="6533817036607128241">"Število najdenih tiskalnikov: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 24f4797..cbab1a6 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Оквир за претрагу је приказан"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Оквир за претрагу је сакривен"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Додај штампач"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Изабери штампач"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Заборави штампач"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Пронађен је <xliff:g id="COUNT">%1$s</xliff:g> штампач"</item>
     <item quantity="other" msgid="6533817036607128241">"Пронађено је <xliff:g id="COUNT">%1$s</xliff:g> штампача"</item>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 2d80858..2286fce 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Sökrutan visas"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Sökrutan är dold"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Lägg till skrivare"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Välj en skrivare"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Ta bort en skrivare"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index 3873d37..55c8687 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kisanduku cha kutafutia kimeonyeshwa"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kisanduku cha kutafutia kimefichwa"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ongeza printa"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Chagua printa"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Sahau printa"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Printa <xliff:g id="COUNT">%1$s</xliff:g> imepatikana"</item>
     <item quantity="other" msgid="6533817036607128241">"Printa <xliff:g id="COUNT">%1$s</xliff:g> zimepatikana"</item>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index 7d6523e..aa01d6f 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"แสดงช่องค้นหาอยู่"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ซ่อนช่องค้นหาอยู่"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"เพิ่มเครื่องพิมพ์"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"เลือกเครื่องพิมพ์"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"ไม่ต้องจำเครื่องพิมพ์"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
     <item quantity="other" msgid="6533817036607128241">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 238c6bc..a72c937 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Ipinapakita ang box para sa paghahanap"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Nakatago ang box para sa paghahanap"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Magdagdag ng printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Piliin ang printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Kalimutan ang printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ang nakita"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (na) printer ang nakita"</item>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index f851f20..c6e302d 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Arama kutusu gösteriliyor"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Arama kutusu gizli"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Yazıcı ekle"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Yazıcı seç"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Yazıcıyı unut"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 8a340f1..4f526d0 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Вікно пошуку показано"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Вікно пошуку сховано"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Додати принтер"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Вибрати принтер"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Ігнорувати принтер"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 7d086ad..d21172c 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Hiển thị hộp tìm kiếm"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Ẩn hộp tìm kiếm"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Thêm máy in"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Chọn máy in"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Bỏ qua máy in"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
     <item quantity="other" msgid="6533817036607128241">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 7e501f1..e43ea60 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜索框已显示"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜索框已隐藏"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"添加打印机"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"选择打印机"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"取消保存打印机"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
     <item quantity="other" msgid="6533817036607128241">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 3856c75..2c2422a9 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜尋框已顯示"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜尋框已隱藏"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"新增打印機"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"選取打印機"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"移除打印機"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
     <item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 81e0627..0fe88d9 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜尋框已顯示"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜尋框已隱藏"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"新增印表機"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"選取印表機"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"移除印表機"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
     <item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index 03c499f..08e31e1 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Ibhokisi lokuhlola libonisiwe"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Ibhokisi lokusesha lifihliwe"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Engeza iphrinta"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Khetha iphrinta"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Khohlwa iphrinta"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> iphrinta itholiwe"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> amaphrinta atholiwe"</item>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 778fb4d..615d667 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
@@ -441,6 +441,7 @@
 
     private void removeObsoletePrintJobs() {
         synchronized (mLock) {
+            boolean persistState = false;
             final int printJobCount = mPrintJobs.size();
             for (int i = printJobCount - 1; i >= 0; i--) {
                 PrintJobInfo printJob = mPrintJobs.get(i);
@@ -450,9 +451,12 @@
                         Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
                     }
                     removePrintJobFileLocked(printJob.getId());
+                    persistState = true;
                 }
             }
-            mPersistanceManager.writeStateLocked();
+            if (persistState) {
+                mPersistanceManager.writeStateLocked();
+            }
         }
     }
 
@@ -799,6 +803,10 @@
                 for (int j = 0; j < printJobCount; j++) {
                     PrintJobInfo printJob = printJobs.get(j);
 
+                    if (!shouldPersistPrintJob(printJob)) {
+                        continue;
+                    }
+
                     serializer.startTag(null, TAG_JOB);
 
                     serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 09ac2da..8d6fe41 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -71,6 +71,9 @@
     <!-- Keyguard -->
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
 
+    <!-- Wifi Display -->
+    <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
+
     <application
         android:persistent="true"
         android:allowClearUserData="false"
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..1c3518a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..9dbc65e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..ddb002d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..43b7ef2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..1d8b7ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
deleted file mode 100644
index 02d7fda..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index 263f07c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/search_light_land.png b/packages/SystemUI/res/drawable-hdpi/search_light_land.png
new file mode 100644
index 0000000..731f19b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..11b2134
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..a858573
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..04de5d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..caea37e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..b66aa46
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
deleted file mode 100644
index 09ae409..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index 780cfc8..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/search_light_land.png b/packages/SystemUI/res/drawable-mdpi/search_light_land.png
new file mode 100644
index 0000000..a4d82f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..10ebcd5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..fef43b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..05e3267
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..ef42b27
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..fc1c95e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
deleted file mode 100644
index 48f90ac..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index 621c045..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/search_light_land.png b/packages/SystemUI/res/drawable-xhdpi/search_light_land.png
new file mode 100644
index 0000000..b62c74e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_available.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_available.png
new file mode 100644
index 0000000..68b1b7c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_available.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connected.png
new file mode 100644
index 0000000..8a8f890
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
new file mode 100644
index 0000000..12d4a01
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
new file mode 100644
index 0000000..3cb4421
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
new file mode 100644
index 0000000..4620b3a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png
deleted file mode 100644
index b07be828..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index f02d0ab..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png b/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png
new file mode 100644
index 0000000..f364577
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/search_light_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml b/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
new file mode 100644
index 0000000..70db2a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2013, 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.
+ */
+-->
+<animation-list
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="false">
+    <item android:drawable="@drawable/ic_qs_cast_connecting_0" android:duration="500" />
+    <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
+    <item android:drawable="@drawable/ic_qs_cast_connecting_2" android:duration="500" />
+    <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
+</animation-list>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index aa365ae..5488a87 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -311,7 +311,7 @@
             android:layout_height="80dp"
             android:layout_width="match_parent"
             android:layout_gravity="center_vertical"
-            android:src="@drawable/search_light"
+            android:src="@drawable/search_light_land"
             android:scaleType="center"
             android:visibility="gone"
             android:contentDescription="@string/accessibility_search_light"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 6f0d857..988d594 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nie gekoppel nie"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk nie"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi af"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skerm"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Draadlose aansig"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Saai na skerm uit"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 686488e..ae0c650 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"አልተገናኘም"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ምንም አውታረ መረብ የለም"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ጠፍቷል"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"የWi-Fi ማሳያ"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ገመድ አልባ ማሳያ"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ማያ ገጽ ውሰድ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ብሩህነት"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ራስ-ሰር"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 214daae..88b6762 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ليست متصلة"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"لا تتوفر شبكة"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏إيقاف Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"‏عرض Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"عرض شاشة لاسلكي"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"بث الشاشة"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"السطوع"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"تلقائي"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 356e7df..b574e79 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -205,8 +205,8 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Няма падключэння"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма сеткi"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi адключаны"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Дысплей Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Бесправадны дысплей"</string>
+    <!-- no translation found for quick_settings_remote_display_no_connection_label (3319785626703585888) -->
+    <skip />
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркасць"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АЎТА"</string>
     <!-- no translation found for ssl_ca_cert_warning (9005954106902053641) -->
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c893490..1814c23 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Няма връзка"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма мрежа"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi е изключен"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Дисплей през Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Безжичен дисплей"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Екран за предаване"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркост"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТ."</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f29b10e..ad7eb5d 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Desconnectat"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hi ha cap xarxa"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desconnectada"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla sense fil"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla d\'emissió"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 76a7201..c74f15c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nepřipojeno"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žádná síť"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi vypnuta"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Displej přes Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bezdrátový displej"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Vzdálená obrazovka"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 3f31217..3da7c6a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke forbundet"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Intet netværk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi slået fra"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådløs skærm"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast-skærm"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 444a555..0e1017b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nicht verbunden"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Kein Netz"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WLAN aus"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WLAN-Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Kabellose Übertragung (WiDi)"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Bildschirm übertragen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helligkeit"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6be551c..1b6929c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Μη συνδεδεμένο"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Κανένα δίκτυο"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ανενεργό"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Οθόνη Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ασύρματη οθόνη"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Μετάδοση οθόνης"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Φωτεινότητα"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ΑΥΤΟΜΑΤΗ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 93efc15..825692d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Not Connected"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 93efc15..825692d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Not Connected"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No Network"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Off"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4c795cb..6202baf 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Sin conexión"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sin red"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivada"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla inalámbrica"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla de Cast"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 9814ae7..154c0ee 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"No conectado"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"No hay red."</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desactivado"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Pantalla Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Pantalla inalámbrica"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Pantalla de Cast"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillo"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 510cce2..fad777c 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ühendus puudub"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Võrku pole"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WiFi-ühendus on väljas"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WiFi-ekraan"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Juhtmeta ekraaniühendus"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast-ekraan"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Heledus"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAATNE"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4d2b1c4..5782975 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"متصل نیست"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"شبکه‌ای موجود نیست"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏Wi-Fi خاموش است"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"نمایش بدون سیم"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"فرستادن صفحه"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"روشنایی"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"خودکار"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 299a0a5..9a715e8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ei yhteyttä"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ei verkkoa"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi-yhteys pois käytöstä"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wifi-näyttö"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Langaton näyttö"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Lähetysnäyttö"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kirkkaus"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2a53193..bb1dbf1 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Affichage Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Affichage sans fil"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Écran distant"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 61260fe..a0eee35 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connecté"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Aucun réseau"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Affichage sans fil"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Écran sur lequel l\'affichage est diffusé"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosité"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATIQUE"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 44273b1..4b1c3bc 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"कनेक्ट नहीं है"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"कोई नेटवर्क नहीं"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi बंद"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi प्रदर्शन"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"वायरलेस डिस्प्ले"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"स्क्रीन कास्ट करें"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"स्क्रीन की रोशनी"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"स्वत:"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7384dd5..afed35c 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nije povezano"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi isključen"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi zaslon"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bežični prikaz"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Emitiranje zaslona"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svjetlina"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKI"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 65605aa..aba5a88 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nincs kapcsolat"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nincs hálózat"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi kikapcsolva"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi kijelző"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Vezeték nélküli kijelző"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Képernyő tartalmának átküldése"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Fényerő"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"automatikus"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index d2f5096..f5793c0 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Միացված չէ"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ցանց չկա"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi-ը անջատված է"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi ցուցադրիչ"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Անլար էկրան"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Հեռակա էկրան"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Պայծառություն"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"Ինքնաշխատ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 32e7c42..0893599 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -176,7 +176,7 @@
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode pesawat"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Mengisi baterai, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
-    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Ditagih"</string>
+    <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"Terisi"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Perangkat)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth Mati"</string>
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Tidak Tersambung"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tidak Ada Jaringan"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Mati"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Tampilan Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Layar Nirkabel"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Layar Transmisi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATIS"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f8790bb..67ae18d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Non connesso"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nessuna rete"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi disattivato"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Display Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Visualizzazione wireless"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Trasmetti schermo"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminosità"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 5dbe432..fe9c458 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"לא מחובר"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"אין רשת"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"‏Wi-Fi כבוי"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"‏תצוגת Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"‏תצוגת Wi-Fi"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"העבר מסך"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"בהירות"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"אוטומטי"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d1ba2a8..13bea42 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"接続されていません"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ネットワークなし"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi OFF"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fiディスプレイ"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ワイヤレスディスプレイ"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"画面のキャスト"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"画面の明るさ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index bd6e87f2..67b29d6 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"არ არის დაკავშირებული."</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ქსელი არ არის"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi გამორთულია"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi ეკრანი"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"უსადენო ეკრანი"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Cast Screen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"განათება"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ავტომატურად"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 20ee33b..4afc08b 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"មិន​បាន​តភ្ជាប់"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"គ្មាន​បណ្ដាញ"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"បិទ​វ៉ាយហ្វាយ"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"បង្ហា​ញ​វ៉ាយហ្វាយ"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"​បង្ហាញ​បណ្ដាញ​ឥត​ខ្សែ"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ចាត់​ថ្នាក់​អេក្រង់"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ពន្លឺ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ស្វ័យប្រវត្តិ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញ​អាច​\nត្រូវ​បាន​ត្រួតពិនិត្យ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cec56e5..ec8bdc1 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"연결되어 있지 않음"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"네트워크가 연결되지 않음"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 꺼짐"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi 디스플레이"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"무선 디스플레이"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"화면 전송"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"밝기"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"자동"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index f62dea2..766477f 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ບໍ່ມີເຄືອຂ່າຍ"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi​-Fi ປິດ"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"ຈໍສະແດງຜົນ Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"ການສະແດງຜົນໄຮ້ສາຍ"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ດຶງໜ້າຈໍ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ຄວາມແຈ້ງ"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"ອັດຕະໂນມັດ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c38b653..4feeae2 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Neprisijungta"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tinklo nėra"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"„Wi-Fi“ išjungta"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"„Wi-Fi“ pateiktis"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Belaidis rodymas"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Perduoti ekraną"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Skaistis"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATINIS"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e969920..01d1108 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nav izveidots savienojums"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nav tīkla"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi ir izslēgts"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi displejs"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bezvadu attēlošana"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Apraides ekrāns"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Spilgtums"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMĀTISKI"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 72d92b5..d92407c 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Холбогдоогүй"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Сүлжээгүй"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi унтарсан"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Дэлгэц"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Утасгүй дэлгэц"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Дамжуулах дэлгэц"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Тодрол"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОМАТ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index dff3279..58613fd 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Tidak Disambungkan"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Tiada Rangkaian"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Dimatikan"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Paparan Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Paparan Wayarles"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Skrin Cast"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Kecerahan"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 66320ce..f75730e 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ikke tilkoblet"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ingen nettverk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi er av"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skjerm"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådløs skjerm"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Send skjermen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Lysstyrke"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 9aa7e75..a05f9c5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Niet verbonden"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Geen netwerk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wifi uit"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wifi-weergave"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Draadloze weergave"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Scherm sturen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Helderheid"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATISCH"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 3fe07e7..83e3c43 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Brak połączenia"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Brak sieci"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wyłącz Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wyświetlacz Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wyświetlacz bezprzewodowy"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Ekran Cast"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jasność"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATYCZNA"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 22eda90..4e318d7 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Não Ligado"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem Rede"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Desligado"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Visualização Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Display Sem Fios"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Transmitir ecrã"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÁTICO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 351965f..f97da2f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Não conectado"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Sem rede"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi desligado"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Display sem fio"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Transmitir tela"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brilho"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 9e1c9b8..5bc11e9 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -362,9 +362,7 @@
     <skip />
     <!-- no translation found for quick_settings_wifi_off_label (7558778100843885864) -->
     <skip />
-    <!-- no translation found for quick_settings_wifi_display_label (6893592964463624333) -->
-    <skip />
-    <!-- no translation found for quick_settings_wifi_display_no_connection_label (2355298740765736918) -->
+    <!-- no translation found for quick_settings_remote_display_no_connection_label (372107699274391290) -->
     <skip />
     <!-- no translation found for quick_settings_brightness_dialog_title (8599674057673605368) -->
     <skip />
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 7415128..168369d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Neconectat"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nicio reţea"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi deconectat"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Afişaj Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ecran wireless"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Ecran de afișare a transmisiunii"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Luminozitate"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMAT"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a587dec..96e6e13 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -200,8 +200,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Нет соединения"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нет сети"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi выкл."</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Проектор Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wi-Fi-монитор"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Wi-Fi-монитор"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яркость"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТОНАСТРОЙКА"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 0b82843..60e4dc2 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nepripojené"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Žiadna sieť"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Sieť Wi-Fi je vypnutá"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Obrazovka Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Bezdrôtový displej"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Vzdialená obrazovka"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Jas"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATICKY"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 6699440..2f90aeb 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Povezava ni vzpostavljena"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ni omrežja"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi izklopljen"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Zaslon Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Prikaz brezžičnih naprav"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Zaslon za predvajanje"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Svetlost"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"SAMODEJNO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 4e990d1..33607f2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Веза није успостављена"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нема мреже"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi је искључен"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi екран"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Бежични екран"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Пребаци екран"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Осветљеност"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АУТОМАТСКА"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 06eccfc..b49b5c9 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Ej ansluten"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Inget nätverk"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi av"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi-skärm"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Trådlös skärm"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Överför skärmen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ljusstyrka"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 6bd8632..ac025fd 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -194,8 +194,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Haijaunganishwa"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Hakuna Mtandao"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi Imezimwa"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Onyesho la Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Uonyeshaji Pasiwaya"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Utumaji wa Skrini"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ung\'avu"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"KIOTOMATIKI"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 6893694..65b075a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"ไม่ได้เชื่อมต่อ"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"ไม่มีเครือข่าย"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"ปิด WiFi"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"การแสดงผล WiFi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"จอแสดงผลไร้สาย"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"ส่งหน้าจอ"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"ความสว่าง"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"อัตโนมัติ"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 6aa4b47..4ac1b53 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Hindi Nakakonekta"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Walang Network"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Naka-off ang Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Display ng Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Wireless Display"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"I-cast ang Screen"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brightness"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 964371f..a15e375 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Bağlı Değil"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ağ yok"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Kablosuz Kapalı"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Kablosuz Ekran"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Kablosuz Ekran"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Yayınlama Ekranı"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Parlaklık"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OTOMATİK"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f502691..439c3d7 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Не під’єднано."</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Немає мережі"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi вимкнено"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Відображення Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Бездротове відображення"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Транслювати екран"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 707f2d8..34d1414 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Chưa được kết nối"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Không có mạng nào"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Tắt Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Hiển thị Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Hiển thị không dây"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Truyền màn hình"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Độ sáng"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"TỰ ĐỘNG"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 87f1893..f759662 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未连接"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"无网络"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"WLAN 已关闭"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"WLAN 显示"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"无线显示"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"投射屏幕"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自动"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 1007f85..bf5ae35 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網絡"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi 關閉"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi Display"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"無線顯示"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"放送螢幕"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index edd6fd2..b1f99f5 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -198,8 +198,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"未連線"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"沒有網路"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"關閉 Wi-Fi"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Wi-Fi 顯示裝置"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"無線螢幕分享"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"投放螢幕"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"亮度"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"自動"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d43ccfc..f284b7c 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -196,8 +196,7 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Akuxhunyiwe"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Ayikho inethiwekhi"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"I-Wi-Fi icimile"</string>
-    <string name="quick_settings_wifi_display_label" msgid="6893592964463624333">"Ukuboniswa kwe-Wi-"</string>
-    <string name="quick_settings_wifi_display_no_connection_label" msgid="2355298740765736918">"Ukubonisa okungenazintambo"</string>
+    <string name="quick_settings_remote_display_no_connection_label" msgid="372107699274391290">"Isikrini sabalingisi"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Ukugqama"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"OKUZENZAKALELAYO"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e6fcdff..e36ca8e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -490,10 +490,8 @@
     <string name="quick_settings_wifi_no_network">No Network</string>
     <!-- QuickSettings: Wifi (Off) [CHAR LIMIT=NONE] -->
     <string name="quick_settings_wifi_off_label">Wi-Fi Off</string>
-    <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_wifi_display_label">Wi-Fi Display</string>
-    <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_wifi_display_no_connection_label">Wireless Display</string>
+    <!-- QuickSettings: Remote display [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_remote_display_no_connection_label">Cast Screen</string>
     <!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
     <string name="quick_settings_brightness_dialog_title">Brightness</string>
     <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCase.java b/packages/SystemUI/src/com/android/systemui/DessertCase.java
index dd4c018..d797e38 100644
--- a/packages/SystemUI/src/com/android/systemui/DessertCase.java
+++ b/packages/SystemUI/src/com/android/systemui/DessertCase.java
@@ -36,7 +36,8 @@
         if (pm.getComponentEnabledSetting(cn) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
             Slog.v("DessertCase", "ACHIEVEMENT UNLOCKED");
             pm.setComponentEnabledSetting(cn,
-                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                    PackageManager.DONT_KILL_APP);
         }
 
         mView = new DessertCaseView(this);
diff --git a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
index 6fce732..4147155 100644
--- a/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/DessertCaseView.java
@@ -496,7 +496,6 @@
     }
 
     public static class RescalingContainer extends FrameLayout {
-        private static final int SYSTEM_UI_MODE_800 = 0x00000800;
         private DessertCaseView mView;
         private float mDarkness;
 
@@ -509,7 +508,7 @@
                     | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                     | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                     | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-                    | SYSTEM_UI_MODE_800
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
             );
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 9839fe9..7d3e870 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -38,7 +38,7 @@
     }
 
     private void updateAnim() {
-        Drawable drawable = getDrawable();
+        Drawable drawable = mAttached ? getDrawable() : null;
         if (mAttached && mAnim != null) {
             mAnim.stop();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 607ce41..bbac4ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2105,9 +2105,12 @@
         }
 
         public void tickerHalting() {
-            mStatusBarContents.setVisibility(View.VISIBLE);
+            if (mStatusBarContents.getVisibility() != View.VISIBLE) {
+                mStatusBarContents.setVisibility(View.VISIBLE);
+                mStatusBarContents
+                        .startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
+            }
             mTickerView.setVisibility(View.GONE);
-            mStatusBarContents.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null));
             // we do not animate the ticker away at this point, just get rid of it (b/6992707)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 37504fb..e7b8fa1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -37,9 +37,8 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LevelListDrawable;
 import android.hardware.display.DisplayManager;
-import android.hardware.display.WifiDisplayStatus;
+import android.media.MediaRouter;
 import android.net.wifi.WifiManager;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -62,6 +61,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.internal.app.MediaRouteDialogPresenter;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.QuickSettingsModel.ActivityState;
 import com.android.systemui.statusbar.phone.QuickSettingsModel.BluetoothState;
@@ -92,9 +92,7 @@
     private QuickSettingsModel mModel;
     private ViewGroup mContainerView;
 
-    private DisplayManager mDisplayManager;
     private DevicePolicyManager mDevicePolicyManager;
-    private WifiDisplayStatus mWifiDisplayStatus;
     private PhoneStatusBar mStatusBarService;
     private BluetoothState mBluetoothState;
     private BluetoothAdapter mBluetoothAdapter;
@@ -118,13 +116,11 @@
             new ArrayList<QuickSettingsTileView>();
 
     public QuickSettings(Context context, QuickSettingsContainerView container) {
-        mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
         mDevicePolicyManager
             = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mContext = context;
         mContainerView = container;
         mModel = new QuickSettingsModel(context);
-        mWifiDisplayStatus = new WifiDisplayStatus();
         mBluetoothState = new QuickSettingsModel.BluetoothState();
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -171,7 +167,6 @@
         mLocationController = locationController;
 
         setupQuickSettings();
-        updateWifiDisplayStatus();
         updateResources();
         applyLocationEnabledStatus();
 
@@ -314,11 +309,19 @@
                 collapsePanels();
                 final UserManager um = UserManager.get(mContext);
                 if (um.getUsers(true).size() > 1) {
-                    try {
-                        WindowManagerGlobal.getWindowManagerService().lockNow(null);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Couldn't show user switcher", e);
-                    }
+                    // Since keyguard and systemui were merged into the same process to save
+                    // memory, they share the same Looper and graphics context.  As a result,
+                    // there's no way to allow concurrent animation while keyguard inflates.
+                    // The workaround is to add a slight delay to allow the animation to finish.
+                    mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            try {
+                                WindowManagerGlobal.getWindowManagerService().lockNow(null);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Couldn't show user switcher", e);
+                            }
+                        }
+                    }, 400); // TODO: ideally this would be tied to the collapse of the panel
                 } else {
                     Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
                             mContext, v, ContactsContract.Profile.CONTENT_URI,
@@ -668,20 +671,33 @@
         });
         parent.addView(alarmTile);
 
-        // Wifi Display
-        QuickSettingsBasicTile wifiDisplayTile
+        // Remote Display
+        QuickSettingsBasicTile remoteDisplayTile
                 = new QuickSettingsBasicTile(mContext);
-        wifiDisplayTile.setImageResource(R.drawable.ic_qs_remote_display);
-        wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
+        remoteDisplayTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+                collapsePanels();
+
+                final Dialog[] dialog = new Dialog[1];
+                dialog[0] = MediaRouteDialogPresenter.createDialog(mContext,
+                        MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                        new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        dialog[0].dismiss();
+                        startSettingsActivity(
+                                android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+                    }
+                });
+                dialog[0].getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+                dialog[0].show();
             }
         });
-        mModel.addWifiDisplayTile(wifiDisplayTile,
-                new QuickSettingsModel.BasicRefreshCallback(wifiDisplayTile)
+        mModel.addRemoteDisplayTile(remoteDisplayTile,
+                new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile)
                         .setShowWhenEnabled(true));
-        parent.addView(wifiDisplayTile);
+        parent.addView(remoteDisplayTile);
 
         if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
             // IME
@@ -816,15 +832,6 @@
         dialog.show();
     }
 
-    private void updateWifiDisplayStatus() {
-        mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
-        applyWifiDisplayStatus();
-    }
-
-    private void applyWifiDisplayStatus() {
-        mModel.onWifiDisplayStateChanged(mWifiDisplayStatus);
-    }
-
     private void applyBluetoothStatus() {
         mModel.onBluetoothStateChange(mBluetoothState);
     }
@@ -848,12 +855,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            if (DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED.equals(action)) {
-                WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
-                        DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
-                mWifiDisplayStatus = status;
-                applyWifiDisplayStatus();
-            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
+            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                         BluetoothAdapter.ERROR);
                 mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 15d655c..e1a20ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -27,7 +27,8 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
-import android.hardware.display.WifiDisplayStatus;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
 import android.net.ConnectivityManager;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -57,7 +58,6 @@
         BrightnessStateChangeCallback,
         RotationLockControllerCallback,
         LocationSettingsChangeCallback {
-
     // Sett InputMethoManagerService
     private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
 
@@ -199,6 +199,30 @@
         }
     }
 
+    /** Callback for changes to remote display routes. */
+    private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
+        @Override
+        public void onRouteAdded(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+    }
+
     private final Context mContext;
     private final Handler mHandler;
     private final CurrentUserTracker mUserTracker;
@@ -206,6 +230,9 @@
     private final BugreportObserver mBugreportObserver;
     private final BrightnessObserver mBrightnessObserver;
 
+    private final MediaRouter mMediaRouter;
+    private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
+
     private final boolean mHasMobileData;
 
     private QuickSettingsTileView mUserTile;
@@ -228,9 +255,9 @@
     private RefreshCallback mWifiCallback;
     private WifiState mWifiState = new WifiState();
 
-    private QuickSettingsTileView mWifiDisplayTile;
-    private RefreshCallback mWifiDisplayCallback;
-    private State mWifiDisplayState = new State();
+    private QuickSettingsTileView mRemoteDisplayTile;
+    private RefreshCallback mRemoteDisplayCallback;
+    private State mRemoteDisplayState = new State();
 
     private QuickSettingsTileView mRSSITile;
     private RefreshCallback mRSSICallback;
@@ -278,12 +305,14 @@
         mContext = context;
         mHandler = new Handler();
         mUserTracker = new CurrentUserTracker(mContext) {
+            @Override
             public void onUserSwitched(int newUserId) {
                 mBrightnessObserver.startObserving();
                 refreshRotationLockTile();
                 onBrightnessLevelChanged();
                 onNextAlarmChanged();
                 onBugreportChanged();
+                rebindMediaRouterAsCurrentUser();
             }
         };
 
@@ -294,6 +323,11 @@
         mBrightnessObserver = new BrightnessObserver(mHandler);
         mBrightnessObserver.startObserving();
 
+        mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        rebindMediaRouterAsCurrentUser();
+
+        mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback();
+
         ConnectivityManager cm = (ConnectivityManager)
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
         mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
@@ -621,24 +655,64 @@
         mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
     }
 
-    // Wifi Display
-    void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mWifiDisplayTile = view;
-        mWifiDisplayCallback = cb;
-    }
-    public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
-        mWifiDisplayState.enabled =
-                (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
-        if (status.getActiveDisplay() != null) {
-            mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
-            mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
-        } else {
-            mWifiDisplayState.label = mContext.getString(
-                    R.string.quick_settings_wifi_display_no_connection_label);
-            mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display;
-        }
-        mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
+    // Remote Display
+    void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mRemoteDisplayTile = view;
+        mRemoteDisplayCallback = cb;
+        final int[] count = new int[1];
+        mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() {
+            @Override
+            public void onPrepare() {
+                mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                        mRemoteDisplayRouteCallback,
+                        MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+                updateRemoteDisplays();
+            }
+            @Override
+            public void onUnprepare() {
+                mMediaRouter.removeCallback(mRemoteDisplayRouteCallback);
+            }
+        });
 
+        updateRemoteDisplays();
+    }
+
+    private void rebindMediaRouterAsCurrentUser() {
+        mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId());
+    }
+
+    private void updateRemoteDisplays() {
+        MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
+                MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        boolean enabled = connectedRoute != null
+                && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        boolean connecting;
+        if (enabled) {
+            connecting = connectedRoute.isConnecting();
+        } else {
+            connectedRoute = null;
+            connecting = false;
+            final int count = mMediaRouter.getRouteCount();
+            for (int i = 0; i < count; i++) {
+                MediaRouter.RouteInfo route = mMediaRouter.getRouteAt(i);
+                if (route.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) {
+                    enabled = true;
+                    break;
+                }
+            }
+        }
+
+        mRemoteDisplayState.enabled = enabled;
+        if (connectedRoute != null) {
+            mRemoteDisplayState.label = connectedRoute.getName().toString();
+            mRemoteDisplayState.iconId = connecting ?
+                    R.drawable.ic_qs_cast_connecting : R.drawable.ic_qs_cast_connected;
+        } else {
+            mRemoteDisplayState.label = mContext.getString(
+                    R.string.quick_settings_remote_display_no_connection_label);
+            mRemoteDisplayState.iconId = R.drawable.ic_qs_cast_available;
+        }
+        mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState);
     }
 
     // IME
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
index 3d520f7..ad18294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
@@ -21,6 +21,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewParent;
 import android.widget.FrameLayout;
 
 /**
@@ -31,14 +32,14 @@
 
     private int mContentLayoutId;
     private int mColSpan;
-    private int mRowSpan;
+    private boolean mPrepared;
+    private OnPrepareListener mOnPrepareListener;
 
     public QuickSettingsTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         mContentLayoutId = -1;
         mColSpan = 1;
-        mRowSpan = 1;
     }
 
     void setColumnSpan(int span) {
@@ -77,4 +78,72 @@
         }
         super.setVisibility(vis);
     }
+
+    public void setOnPrepareListener(OnPrepareListener listener) {
+        if (mOnPrepareListener != listener) {
+            mOnPrepareListener = listener;
+            mPrepared = false;
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    updatePreparedState();
+                }
+            });
+        }
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        updatePreparedState();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        updatePreparedState();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        updatePreparedState();
+    }
+
+    private void updatePreparedState() {
+        if (mOnPrepareListener != null) {
+            if (isParentVisible()) {
+                if (!mPrepared) {
+                    mPrepared = true;
+                    mOnPrepareListener.onPrepare();
+                }
+            } else if (mPrepared) {
+                mPrepared = false;
+                mOnPrepareListener.onUnprepare();
+            }
+        }
+    }
+
+    private boolean isParentVisible() {
+        if (!isAttachedToWindow()) {
+            return false;
+        }
+        for (ViewParent current = getParent(); current instanceof View;
+                current = current.getParent()) {
+            View view = (View)current;
+            if (view.getVisibility() != VISIBLE) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Called when the view's parent becomes visible or invisible to provide
+     * an opportunity for the client to provide new content.
+     */
+    public interface OnPrepareListener {
+        void onPrepare();
+        void onUnprepare();
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index dca5e41..6eb88be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -22,7 +22,7 @@
 import android.graphics.Canvas;
 import android.os.SystemClock;
 import android.util.AttributeSet;
-import android.util.Log;
+import android.util.Slog;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -75,7 +75,7 @@
         mVertical = (index == VERTICAL);
 
         if (DEBUG)
-            Log.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
+            Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
                     + (mVertical ? " vertical" : " horizontal"));
 
         setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash));
@@ -106,7 +106,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (DEBUG) {
-            Log.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
+            Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
         }
 
         final int action = event.getAction();
@@ -114,12 +114,12 @@
             poke(event);
         } else if (action == MotionEvent.ACTION_DOWN) {
             if (DEBUG) {
-                Log.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
+                Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
             }
             int size = (int) getSize(event.getEventTime());
             if ((mVertical && event.getX() < size) || event.getY() < size) {
                 if (CHATTY) {
-                    Log.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
+                    Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
                 }
                 if (mShouldFlash) {
                     post(mDebugFlash);
@@ -134,7 +134,7 @@
     public void poke(MotionEvent event) {
         mLastPokeTime = event.getEventTime();
         if (DEBUG)
-            Log.v(TAG, "poked! size=" + getSize(mLastPokeTime));
+            Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
         if (mShouldFlash) postInvalidate();
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index c38ad04..0ce4b12 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -37,8 +37,9 @@
     private static final boolean DEBUG = false;
 
     private static final int TRANSIENT_BAR_NONE = 0;
-    private static final int TRANSIENT_BAR_SHOWING = 1;
-    private static final int TRANSIENT_BAR_HIDING = 2;
+    private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1;
+    private static final int TRANSIENT_BAR_SHOWING = 2;
+    private static final int TRANSIENT_BAR_HIDING = 3;
 
     private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
 
@@ -73,13 +74,9 @@
         mWin = win;
     }
 
-    public boolean isHidden() {
-        return mState == StatusBarManager.WINDOW_STATE_HIDDEN;
-    }
-
     public void showTransient() {
         if (mWin != null) {
-            setTransientBarState(TRANSIENT_BAR_SHOWING);
+            setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
         }
     }
 
@@ -87,6 +84,10 @@
         return mTransientBarState == TRANSIENT_BAR_SHOWING;
     }
 
+    public boolean isTransientShowRequested() {
+        return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
+    }
+
     public boolean wasRecentlyTranslucent() {
         return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
     }
@@ -198,6 +199,9 @@
         if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
             if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
             return false;
+        } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested");
+            return false;
         } else if (mWin == null) {
             if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
             return false;
@@ -211,12 +215,13 @@
 
     public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
         if (mWin == null) return vis;
-        if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
+        if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
             if (transientAllowed) {
                 vis |= mTransientFlag;
                 if ((oldVis & mTransientFlag) == 0) {
                     vis |= mUnhideFlag;  // tell sysui we're ready to unhide
                 }
+                setTransientBarState(TRANSIENT_BAR_SHOWING);  // request accepted
             } else {
                 setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
             }
@@ -254,6 +259,7 @@
     private static String transientBarStateToString(int state) {
         if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
         if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
+        if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED";
         if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
         throw new IllegalArgumentException("Unknown state " + state);
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index faca949..c33bd35 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3468,6 +3468,11 @@
                 }
                 // Maintain fullscreen layout until incoming animation is complete.
                 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
+                // Transient status bar on the lockscreen is not allowed
+                if (mForceStatusBarFromKeyguard && mStatusBarController.isTransientShowing()) {
+                    mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
+                            mLastSystemUiFlags, mLastSystemUiFlags);
+                }
             } else if (mTopFullscreenOpaqueWindowState != null) {
                 if (localLOGV) {
                     Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
@@ -5158,9 +5163,9 @@
                 mNavigationBar != null &&
                 hideNavBarSysui && immersiveSticky;
 
-        boolean denyTransientStatus = mStatusBarController.isTransientShowing()
+        boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
                 && !transientStatusBarAllowed && hideStatusBarSysui;
-        boolean denyTransientNav = mNavigationBarController.isTransientShowing()
+        boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
                 && !transientNavBarAllowed;
         if (denyTransientStatus || denyTransientNav) {
             // clear the clearable flags instead
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index bf22e2f..1357462 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -40,6 +40,14 @@
     private KeyguardState mKeyguardState = new KeyguardState();
 
     /* package */ static final class KeyguardState {
+        KeyguardState() {
+            // Assume keyguard is showing and secure until we know for sure. This is here in
+            // the event something checks before the service is actually started.
+            // KeyguardService itself should default to this state until the real state is known.
+            showing = true;
+            showingAndNotHidden = true;
+            secure = true;
+        }
         boolean showing;
         boolean showingAndNotHidden;
         boolean inputRestricted;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index a04ee14..baef607 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -46,6 +46,8 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.ContentObserver;
@@ -146,6 +148,7 @@
     static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
 
     static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
+    static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
 
     // How often we perform a backup pass.  Privileged external callers can
     // trigger an immediate pass.
@@ -251,10 +254,13 @@
     volatile boolean mClearingData;
 
     // Transport bookkeeping
+    final HashMap<String,String> mTransportNames
+            = new HashMap<String,String>();             // component name -> registration name
     final HashMap<String,IBackupTransport> mTransports
-            = new HashMap<String,IBackupTransport>();
+            = new HashMap<String,IBackupTransport>();   // registration name -> binder
+    final ArrayList<TransportConnection> mTransportConnections
+            = new ArrayList<TransportConnection>();
     String mCurrentTransport;
-    IBackupTransport mLocalTransport, mGoogleTransport;
     ActiveRestoreSession mActiveRestoreSession;
 
     // Watch the device provisioning operation during setup
@@ -815,13 +821,7 @@
         }
 
         // Set up our transport options and initialize the default transport
-        // TODO: Have transports register themselves somehow?
         // TODO: Don't create transports that we don't need to?
-        mLocalTransport = new LocalTransport(context);  // This is actually pretty cheap
-        ComponentName localName = new ComponentName(context, LocalTransport.class);
-        registerTransport(localName.flattenToShortString(), mLocalTransport);
-
-        mGoogleTransport = null;
         mCurrentTransport = Settings.Secure.getString(context.getContentResolver(),
                 Settings.Secure.BACKUP_TRANSPORT);
         if ("".equals(mCurrentTransport)) {
@@ -829,28 +829,43 @@
         }
         if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
 
-        // Attach to the Google backup transport.  When this comes up, it will set
-        // itself as the current transport because we explicitly reset mCurrentTransport
-        // to null.
-        ComponentName transportComponent = new ComponentName("com.google.android.backup",
-                "com.google.android.backup.BackupTransportService");
-        try {
-            // If there's something out there that is supposed to be the Google
-            // backup transport, make sure it's legitimately part of the OS build
-            // and not an app lying about its package name.
-            ApplicationInfo info = mPackageManager.getApplicationInfo(
-                    transportComponent.getPackageName(), 0);
-            if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                if (DEBUG) Slog.v(TAG, "Binding to Google transport");
-                Intent intent = new Intent().setComponent(transportComponent);
-                context.bindServiceAsUser(intent, mGoogleConnection, Context.BIND_AUTO_CREATE,
-                        UserHandle.OWNER);
-            } else {
-                Slog.w(TAG, "Possible Google transport spoof: ignoring " + info);
+        // Find transport hosts and bind to their services
+        Intent transportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST);
+        List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
+                transportServiceIntent, 0, UserHandle.USER_OWNER);
+        if (DEBUG) {
+            Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
+        }
+        if (hosts != null) {
+            if (MORE_DEBUG) {
+                for (int i = 0; i < hosts.size(); i++) {
+                    ServiceInfo info = hosts.get(i).serviceInfo;
+                    Slog.v(TAG, "   " + info.packageName + "/" + info.name);
+                }
             }
-        } catch (PackageManager.NameNotFoundException nnf) {
-            // No such package?  No binding.
-            if (DEBUG) Slog.v(TAG, "Google transport not present");
+            for (int i = 0; i < hosts.size(); i++) {
+                try {
+                    ServiceInfo info = hosts.get(i).serviceInfo;
+                    PackageInfo packInfo = mPackageManager.getPackageInfo(info.packageName, 0);
+                    if ((packInfo.applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
+                        ComponentName svcName = new ComponentName(info.packageName, info.name);
+                        if (DEBUG) {
+                            Slog.i(TAG, "Binding to transport host " + svcName);
+                        }
+                        Intent intent = new Intent(transportServiceIntent);
+                        intent.setComponent(svcName);
+                        TransportConnection connection = new TransportConnection();
+                        mTransportConnections.add(connection);
+                        context.bindServiceAsUser(intent,
+                                connection, Context.BIND_AUTO_CREATE,
+                                UserHandle.OWNER);
+                    } else {
+                        Slog.w(TAG, "Transport package not privileged: " + info.packageName);
+                    }
+                } catch (Exception e) {
+                    Slog.e(TAG, "Problem resolving transport service: " + e.getMessage());
+                }
+            }
         }
 
         // Now that we know about valid backup participants, parse any
@@ -1298,13 +1313,16 @@
 
     // Add a transport to our set of available backends.  If 'transport' is null, this
     // is an unregistration, and the transport's entry is removed from our bookkeeping.
-    private void registerTransport(String name, IBackupTransport transport) {
+    private void registerTransport(String name, String component, IBackupTransport transport) {
         synchronized (mTransports) {
-            if (DEBUG) Slog.v(TAG, "Registering transport " + name + " = " + transport);
+            if (DEBUG) Slog.v(TAG, "Registering transport "
+                    + component + "::" + name + " = " + transport);
             if (transport != null) {
                 mTransports.put(name, transport);
+                mTransportNames.put(component, name);
             } else {
-                mTransports.remove(name);
+                mTransports.remove(mTransportNames.get(component));
+                mTransportNames.remove(component);
                 // Nothing further to do in the unregistration case
                 return;
             }
@@ -1390,18 +1408,23 @@
         }
     };
 
-    // ----- Track connection to GoogleBackupTransport service -----
-    ServiceConnection mGoogleConnection = new ServiceConnection() {
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG) Slog.v(TAG, "Connected to Google transport");
-            mGoogleTransport = IBackupTransport.Stub.asInterface(service);
-            registerTransport(name.flattenToShortString(), mGoogleTransport);
+    // ----- Track connection to transports service -----
+    class TransportConnection implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+            if (DEBUG) Slog.v(TAG, "Connected to transport " + component);
+            try {
+                IBackupTransport transport = IBackupTransport.Stub.asInterface(service);
+                registerTransport(transport.name(), component.flattenToShortString(), transport);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to register transport " + component);
+            }
         }
 
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG) Slog.v(TAG, "Disconnected from Google transport");
-            mGoogleTransport = null;
-            registerTransport(name.flattenToShortString(), null);
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (DEBUG) Slog.v(TAG, "Disconnected from transport " + component);
+            registerTransport(null, component.flattenToShortString(), null);
         }
     };
 
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 594f683..baff661 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -3380,6 +3380,11 @@
             String pacFileUrl = "";
             if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
                     !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
+                if (!proxyProperties.isValid()) {
+                    if (DBG)
+                        log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
+                    return;
+                }
                 mGlobalProxy = new ProxyProperties(proxyProperties);
                 host = mGlobalProxy.getHost();
                 port = mGlobalProxy.getPort();
@@ -3423,6 +3428,11 @@
             } else {
                 proxyProperties = new ProxyProperties(host, port, exclList);
             }
+            if (!proxyProperties.isValid()) {
+                if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
+                return;
+            }
+
             synchronized (mProxyLock) {
                 mGlobalProxy = proxyProperties;
             }
@@ -3447,6 +3457,10 @@
         synchronized (mProxyLock) {
             if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
             if (mDefaultProxy == proxy) return; // catches repeated nulls
+            if (proxy != null &&  !proxy.isValid()) {
+                if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
+                return;
+            }
             mDefaultProxy = proxy;
 
             if (mGlobalProxy != null) return;
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 8cc80f7..2bb99d6 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -56,6 +56,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.net.ProxyProperties;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -522,6 +523,7 @@
                         || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
                     removed = true;
                     policy.mAdminList.remove(i);
+                    policy.mAdminMap.remove(aa.info.getComponent());
                 }
             } catch (RemoteException re) {
                 // Shouldn't happen
@@ -2463,6 +2465,12 @@
         }
         exclusionList = exclusionList.trim();
         ContentResolver res = mContext.getContentResolver();
+
+        ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
+        if (!proxyProperties.isValid()) {
+            Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
+            return;
+        }
         Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
         Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
         Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 8eaa91d..399e7d1 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -123,6 +123,18 @@
 # ---------------------------
 # Out of memory for surfaces.
 31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
+# Task created.
+31001 wm_task_created (TaskId|1|5),(StackId|1|5)
+# Task moved to top (1) or bottom (0).
+31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
+# Task removed with source explanation.
+31003 wm_task_removed (TaskId|1|5),(Reason|3)
+# Stack created.
+31004 wm_stack_created (StackId|1|5),(RelativeBoxId|1|5),(Position|1),(Weight|1|6)
+# Home stack moved to top (1) or bottom (0).
+31005 wm_home_stack_moved (ToTop|1)
+# Stack removed.
+31006 wm_stack_removed (StackId|1|5)
 
 
 # ---------------------------
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/java/com/android/server/LockSettingsService.java
index cd746cf..35e7afa 100644
--- a/services/java/com/android/server/LockSettingsService.java
+++ b/services/java/com/android/server/LockSettingsService.java
@@ -154,11 +154,11 @@
     }
 
     private final void checkWritePermission(int userId) {
-        mContext.checkCallingOrSelfPermission(PERMISSION);
+        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
     }
 
     private final void checkPasswordReadPermission(int userId) {
-        mContext.checkCallingOrSelfPermission(PERMISSION);
+        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
     }
 
     private final void checkReadPermission(String requestedKey, int userId) {
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
index e0f415b..16d2468 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/java/com/android/server/NsdService.java
@@ -483,10 +483,14 @@
                         clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
 
                         stopResolveService(id);
-                        if (!getAddrInfo(id, cooked[3])) {
+                        removeRequestMap(clientId, id, clientInfo);
+
+                        int id2 = getUniqueId();
+                        if (getAddrInfo(id2, cooked[3])) {
+                            storeRequestMap(clientId, id2, clientInfo);
+                        } else {
                             clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
                                     NsdManager.FAILURE_INTERNAL_ERROR, clientId);
-                            removeRequestMap(clientId, id, clientInfo);
                             clientInfo.mResolvedService = null;
                         }
                         break;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bb14259..a42cbcf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -55,6 +55,7 @@
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 import com.android.server.input.InputManagerService;
+import com.android.server.media.MediaRouterService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.os.SchedulingPolicyService;
@@ -356,6 +357,7 @@
         DreamManagerService dreamy = null;
         AssetAtlasService atlas = null;
         PrintManagerService printManager = null;
+        MediaRouterService mediaRouter = null;
 
         // Bring up services needed for UI.
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
@@ -804,6 +806,16 @@
             } catch (Throwable e) {
                 reportWtf("starting Print Service", e);
             }
+
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Media Router Service");
+                    mediaRouter = new MediaRouterService(context);
+                    ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
+                } catch (Throwable e) {
+                    reportWtf("starting MediaRouterService", e);
+                }
+            }
         }
 
         // Before things start rolling, be sure we have decided whether
@@ -916,6 +928,7 @@
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final PrintManagerService printManagerF = printManager;
+        final MediaRouterService mediaRouterF = mediaRouter;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -1063,6 +1076,12 @@
                 } catch (Throwable e) {
                     reportWtf("Notifying PrintManagerService running", e);
                 }
+
+                try {
+                    if (mediaRouterF != null) mediaRouterF.systemRunning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying MediaRouterService running", e);
+                }
             }
         });
 
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index c1a60ee..e6b6b93 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -40,6 +40,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.graphics.Point;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -637,6 +638,14 @@
         return false;
     }
 
+    private Point getDefaultDisplaySize() {
+        Point p = new Point();
+        WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+        Display d = wm.getDefaultDisplay();
+        d.getRealSize(p);
+        return p;
+    }
+
     public void setDimensionHints(int width, int height) throws RemoteException {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
         synchronized (mLock) {
@@ -648,10 +657,10 @@
             if (width <= 0 || height <= 0) {
                 throw new IllegalArgumentException("width and height must be > 0");
             }
-            // Make sure it is at least as large as the display's maximum size.
-            int maxSizeDimension = getMaximumSizeDimension();
-            width = Math.max(width, maxSizeDimension);
-            height = Math.max(height, maxSizeDimension);
+            // Make sure it is at least as large as the display.
+            Point displaySize = getDefaultDisplaySize();
+            width = Math.max(width, displaySize.x);
+            height = Math.max(height, displaySize.y);
 
             if (width != wallpaper.width || height != wallpaper.height) {
                 wallpaper.width = width;
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index f972f70..aa9849e 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -190,10 +190,10 @@
         private final HashMap<String, Account[]> accountCache =
                 new LinkedHashMap<String, Account[]>();
         /** protected by the {@link #cacheLock} */
-        private HashMap<Account, HashMap<String, String>> userDataCache =
+        private final HashMap<Account, HashMap<String, String>> userDataCache =
                 new HashMap<Account, HashMap<String, String>>();
         /** protected by the {@link #cacheLock} */
-        private HashMap<Account, HashMap<String, String>> authTokenCache =
+        private final HashMap<Account, HashMap<String, String>> authTokenCache =
                 new HashMap<Account, HashMap<String, String>>();
 
         UserAccounts(Context context, int userId) {
@@ -475,6 +475,7 @@
         validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
     }
 
+    @Override
     public String getPassword(Account account) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getPassword: " + account
@@ -514,6 +515,7 @@
         }
     }
 
+    @Override
     public String getUserData(Account account, String key) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getUserData: " + account
@@ -533,6 +535,7 @@
         }
     }
 
+    @Override
     public AuthenticatorDescription[] getAuthenticatorTypes() {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAuthenticatorTypes: "
@@ -763,6 +766,7 @@
         return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
     }
 
+    @Override
     public void hasFeatures(IAccountManagerResponse response,
             Account account, String[] features) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -840,6 +844,7 @@
         }
     }
 
+    @Override
     public void removeAccount(IAccountManagerResponse response, Account account) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "removeAccount: " + account
@@ -1049,6 +1054,7 @@
         }
     }
 
+    @Override
     public String peekAuthToken(Account account, String authTokenType) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "peekAuthToken: " + account
@@ -1068,6 +1074,7 @@
         }
     }
 
+    @Override
     public void setAuthToken(Account account, String authTokenType, String authToken) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "setAuthToken: " + account
@@ -1087,6 +1094,7 @@
         }
     }
 
+    @Override
     public void setPassword(Account account, String password) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "setAuthToken: " + account
@@ -1135,6 +1143,7 @@
         mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
     }
 
+    @Override
     public void clearPassword(Account account) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "clearPassword: " + account
@@ -1152,6 +1161,7 @@
         }
     }
 
+    @Override
     public void setUserData(Account account, String key, String value) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "setUserData: " + account
@@ -1225,6 +1235,7 @@
         }
     }
 
+    @Override
     public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
                                   final String authTokenType)
             throws RemoteException {
@@ -1271,6 +1282,7 @@
         }
     }
 
+    @Override
     public void getAuthToken(IAccountManagerResponse response, final Account account,
             final String authTokenType, final boolean notifyOnAuthFailure,
             final boolean expectActivityLaunch, Bundle loginOptionsIn) {
@@ -1284,8 +1296,22 @@
                     + ", pid " + Binder.getCallingPid());
         }
         if (response == null) throw new IllegalArgumentException("response is null");
-        if (account == null) throw new IllegalArgumentException("account is null");
-        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
+        try {
+            if (account == null) {
+                Slog.w(TAG, "getAuthToken called with null account");
+                response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null");
+                return;
+            }
+            if (authTokenType == null) {
+                Slog.w(TAG, "getAuthToken called with null authTokenType");
+                response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null");
+                return;
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to report error back to the client." + e);
+            return;
+        }
+
         checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
         final UserAccounts accounts = getUserAccountsForCaller();
         final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
@@ -1294,11 +1320,6 @@
         final boolean customTokens =
             authenticatorInfo != null && authenticatorInfo.type.customTokens;
 
-        // Check to see that the app is authorized to access the account, in case it's a
-        // restricted account.
-        if (!ArrayUtils.contains(getAccounts((String) null), account)) {
-            throw new IllegalArgumentException("no such account");
-        }
         // skip the check if customTokens
         final int callerUid = Binder.getCallingUid();
         final boolean permissionGranted = customTokens ||
@@ -1472,6 +1493,7 @@
         return id;
     }
 
+    @Override
     public void addAccount(final IAccountManagerResponse response, final String accountType,
             final String authTokenType, final String[] requiredFeatures,
             final boolean expectActivityLaunch, final Bundle optionsIn) {
@@ -1582,6 +1604,7 @@
         }
     }
 
+    @Override
     public void updateCredentials(IAccountManagerResponse response, final Account account,
             final String authTokenType, final boolean expectActivityLaunch,
             final Bundle loginOptions) {
@@ -1620,6 +1643,7 @@
         }
     }
 
+    @Override
     public void editProperties(IAccountManagerResponse response, final String accountType,
             final boolean expectActivityLaunch) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1657,7 +1681,7 @@
         private volatile Account[] mAccountsOfType = null;
         private volatile ArrayList<Account> mAccountsWithFeatures = null;
         private volatile int mCurrentAccount = 0;
-        private int mCallingUid;
+        private final int mCallingUid;
 
         public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
                 IAccountManagerResponse response, String type, String[] features, int callingUid) {
@@ -1941,6 +1965,7 @@
         return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
     }
 
+    @Override
     public void getAccountsByFeatures(IAccountManagerResponse response,
             String type, String[] features) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2069,6 +2094,7 @@
             unbind();
         }
 
+        @Override
         public void binderDied() {
             mResponse = null;
             close();
@@ -2112,6 +2138,7 @@
             mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
         }
 
+        @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
             try {
@@ -2122,6 +2149,7 @@
             }
         }
 
+        @Override
         public void onServiceDisconnected(ComponentName name) {
             mAuthenticator = null;
             IAccountManagerResponse response = getResponseAndClose();
@@ -2217,7 +2245,14 @@
                             Log.v(TAG, getClass().getSimpleName()
                                     + " calling onResult() on response " + response);
                         }
-                        response.onResult(result);
+                        if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) &&
+                                (intent == null)) {
+                            // All AccountManager error codes are greater than 0
+                            response.onError(result.getInt(AccountManager.KEY_ERROR_CODE),
+                                    result.getString(AccountManager.KEY_ERROR_MESSAGE));
+                        } else {
+                            response.onResult(result);
+                        }
                     }
                 } catch (RemoteException e) {
                     // if the caller is dead then there is no one to care about remote exceptions
@@ -2228,10 +2263,12 @@
             }
         }
 
+        @Override
         public void onRequestContinued() {
             mNumRequestContinued++;
         }
 
+        @Override
         public void onError(int errorCode, String errorMessage) {
             mNumErrors++;
             IAccountManagerResponse response = getResponseAndClose();
@@ -2731,6 +2768,7 @@
         return true;
     }
 
+    @Override
     public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
             throws RemoteException {
         final int callingUid = getCallingUid();
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index ea0b978a..933247e 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -307,7 +307,7 @@
         ServiceRecord r = res.record;
         NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                 callingUid, r.packageName, service, service.getFlags(), null);
-        if (unscheduleServiceRestartLocked(r, callingUid)) {
+        if (unscheduleServiceRestartLocked(r, callingUid, false)) {
             if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
         }
         r.lastActivity = SystemClock.uptimeMillis();
@@ -701,7 +701,7 @@
         final long origId = Binder.clearCallingIdentity();
 
         try {
-            if (unscheduleServiceRestartLocked(s, callerApp.info.uid)) {
+            if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
                 if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
                         + s);
             }
@@ -1002,14 +1002,11 @@
                     smap.mServicesByIntent.put(filter, r);
 
                     // Make sure this component isn't in the pending list.
-                    int N = mPendingServices.size();
-                    for (int i=0; i<N; i++) {
+                    for (int i=mPendingServices.size()-1; i>=0; i--) {
                         ServiceRecord pr = mPendingServices.get(i);
                         if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
                                 && pr.name.equals(name)) {
                             mPendingServices.remove(i);
-                            i--;
-                            N--;
                         }
                     }
                 }
@@ -1101,6 +1098,14 @@
             boolean allowCancel) {
         boolean canceled = false;
 
+        ServiceMap smap = getServiceMap(r.userId);
+        if (smap.mServicesByName.get(r.name) != r) {
+            ServiceRecord cur = smap.mServicesByName.get(r.name);
+            Slog.wtf(TAG, "Attempting to schedule restart of " + r
+                    + " when found in map: " + cur);
+            return false;
+        }
+
         final long now = SystemClock.uptimeMillis();
 
         if ((r.serviceInfo.applicationInfo.flags
@@ -1187,6 +1192,7 @@
         if (!mRestartingServices.contains(r)) {
             r.createdFromFg = false;
             mRestartingServices.add(r);
+            r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
         }
 
         r.cancelNotification();
@@ -1209,8 +1215,9 @@
         bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
     }
 
-    private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid) {
-        if (r.restartDelay == 0) {
+    private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid,
+            boolean force) {
+        if (!force && r.restartDelay == 0) {
             return false;
         }
         // Remove from the restarting list; if the service is currently on the
@@ -1220,10 +1227,32 @@
         if (removed || callingUid != r.appInfo.uid) {
             r.resetRestartCounter();
         }
+        if (removed) {
+            clearRestartingIfNeededLocked(r);
+        }
         mAm.mHandler.removeCallbacks(r.restarter);
         return true;
     }
 
+    private void clearRestartingIfNeededLocked(ServiceRecord r) {
+        if (r.restartTracker != null) {
+            // If this is the last restarting record with this tracker, then clear
+            // the tracker's restarting state.
+            boolean stillTracking = false;
+            for (int i=mRestartingServices.size()-1; i>=0; i--) {
+                if (mRestartingServices.get(i).restartTracker == r.restartTracker) {
+                    stillTracking = true;
+                    break;
+                }
+            }
+            if (!stillTracking) {
+                r.restartTracker.setRestarting(false, mAm.mProcessStats.getMemFactorLocked(),
+                        SystemClock.uptimeMillis());
+                r.restartTracker = null;
+            }
+        }
+    }
+
     private final String bringUpServiceLocked(ServiceRecord r,
             int intentFlags, boolean execInFg, boolean whileRestarting) {
         //Slog.i(TAG, "Bring up service:");
@@ -1243,7 +1272,9 @@
 
         // We are now bringing the service up, so no longer in the
         // restarting state.
-        mRestartingServices.remove(r);
+        if (mRestartingServices.remove(r)) {
+            clearRestartingIfNeededLocked(r);
+        }
 
         // Make sure this service is no longer considered delayed, we are starting it now.
         if (r.delayed) {
@@ -1383,6 +1414,7 @@
         } finally {
             if (!created) {
                 app.services.remove(r);
+                r.app = null;
                 scheduleServiceRestartLocked(r, false);
             }
         }
@@ -1553,16 +1585,13 @@
         smap.mServicesByName.remove(r.name);
         smap.mServicesByIntent.remove(r.intent);
         r.totalRestartCount = 0;
-        unscheduleServiceRestartLocked(r, 0);
+        unscheduleServiceRestartLocked(r, 0, true);
 
         // Also make sure it is not on the pending list.
-        int N = mPendingServices.size();
-        for (int i=0; i<N; i++) {
+        for (int i=mPendingServices.size()-1; i>=0; i--) {
             if (mPendingServices.get(i) == r) {
                 mPendingServices.remove(i);
                 if (DEBUG_SERVICE) Slog.v(TAG, "Removed pending: " + r);
-                i--;
-                N--;
             }
         }
 
@@ -1581,6 +1610,7 @@
             }
             r.app.services.remove(r);
             if (r.app.thread != null) {
+                updateServiceForegroundLocked(r.app, false);
                 try {
                     bumpServiceExecutingLocked(r, false, "destroy");
                     mDestroyingServices.add(r);
@@ -1591,7 +1621,6 @@
                             + r.shortName, e);
                     serviceProcessGoneLocked(r);
                 }
-                updateServiceForegroundLocked(r.app, false);
             } else {
                 if (DEBUG_SERVICE) Slog.v(
                     TAG, "Removed service that has no process: " + r);
@@ -1769,6 +1798,7 @@
             long now = SystemClock.uptimeMillis();
             r.tracker.setExecuting(false, memFactor, now);
             r.tracker.setBound(false, memFactor, now);
+            r.tracker.setStarted(false, memFactor, now);
         }
         serviceDoneExecutingLocked(r, true, true);
     }
@@ -1816,6 +1846,12 @@
                     r.tracker = null;
                 }
             }
+            if (finishing) {
+                if (r.app != null) {
+                    r.app.services.remove(r);
+                }
+                r.app = null;
+            }
         }
     }
 
@@ -1894,6 +1930,7 @@
                 Slog.i(TAG, "  Force stopping service " + service);
                 if (service.app != null) {
                     service.app.removed = true;
+                    service.app.services.remove(service);
                 }
                 service.app = null;
                 service.isolatedProc = null;
@@ -1960,8 +1997,7 @@
         }
     }
 
-    final void killServicesLocked(ProcessRecord app,
-            boolean allowRestart) {
+    final void killServicesLocked(ProcessRecord app, boolean allowRestart) {
         // Report disconnected services.
         if (false) {
             // XXX we are letting the client link to the service for
@@ -1990,20 +2026,15 @@
             }
         }
 
-        // Clean up any connections this application has to other services.
-        for (int i=app.connections.size()-1; i>=0; i--) {
-            ConnectionRecord r = app.connections.valueAt(i);
-            removeConnectionLocked(r, app, null);
-        }
-        app.connections.clear();
-
+        // First clear app state from services.
         for (int i=app.services.size()-1; i>=0; i--) {
-            // Any services running in the application need to be placed
-            // back in the pending list.
             ServiceRecord sr = app.services.valueAt(i);
             synchronized (sr.stats.getBatteryStats()) {
                 sr.stats.stopLaunchedLocked();
             }
+            if (sr.app != null) {
+                sr.app.services.remove(sr);
+            }
             sr.app = null;
             sr.isolatedProc = null;
             sr.executeNesting = 0;
@@ -2020,8 +2051,33 @@
                 b.binder = null;
                 b.requested = b.received = b.hasBound = false;
             }
+        }
 
-            if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
+        // Clean up any connections this application has to other services.
+        for (int i=app.connections.size()-1; i>=0; i--) {
+            ConnectionRecord r = app.connections.valueAt(i);
+            removeConnectionLocked(r, app, null);
+        }
+        app.connections.clear();
+
+        ServiceMap smap = getServiceMap(app.userId);
+
+        // Now do remaining service cleanup.
+        for (int i=app.services.size()-1; i>=0; i--) {
+            ServiceRecord sr = app.services.valueAt(i);
+            // Sanity check: if the service listed for the app is not one
+            // we actually are maintaining, drop it.
+            if (smap.mServicesByName.get(sr.name) != sr) {
+                ServiceRecord cur = smap.mServicesByName.get(sr.name);
+                Slog.wtf(TAG, "Service " + sr + " in process " + app
+                        + " not same as in map: " + cur);
+                app.services.removeAt(i);
+                continue;
+            }
+
+            // Any services running in the application may need to be placed
+            // back in the pending list.
+            if (allowRestart && sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
                     &ApplicationInfo.FLAG_PERSISTENT) == 0) {
                 Slog.w(TAG, "Service crashed " + sr.crashCount
                         + " times, stopping: " + sr);
@@ -2054,6 +2110,23 @@
 
         if (!allowRestart) {
             app.services.clear();
+
+            // Make sure there are no more restarting services for this process.
+            for (int i=mRestartingServices.size()-1; i>=0; i--) {
+                ServiceRecord r = mRestartingServices.get(i);
+                if (r.processName.equals(app.processName) &&
+                        r.serviceInfo.applicationInfo.uid == app.info.uid) {
+                    mRestartingServices.remove(i);
+                    clearRestartingIfNeededLocked(r);
+                }
+            }
+            for (int i=mPendingServices.size()-1; i>=0; i--) {
+                ServiceRecord r = mPendingServices.get(i);
+                if (r.processName.equals(app.processName) &&
+                        r.serviceInfo.applicationInfo.uid == app.info.uid) {
+                    mPendingServices.remove(i);
+                }
+            }
         }
 
         // Make sure we have no more records on the stopping list.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 164e7b7..9201b1d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2149,7 +2149,8 @@
                                 totalUTime += otherUTime;
                                 totalSTime += otherSTime;
                                 if (pr != null) {
-                                    BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
+                                    BatteryStatsImpl.Uid.Proc ps = bstats.getProcessStatsLocked(
+                                            st.name, st.pid);
                                     ps.addCpuTimeLocked(st.rel_utime-otherUTime,
                                             st.rel_stime-otherSTime);
                                     ps.addSpeedStepTimes(cpuSpeedTimes);
@@ -2769,10 +2770,10 @@
                     app.processName, uid, uid, gids, debugFlags, mountExternal,
                     app.info.targetSdkVersion, app.info.seinfo, null);
 
-            BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
+            BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
             synchronized (bs) {
                 if (bs.isOnBattery()) {
-                    app.batteryStats.incStartsLocked();
+                    bs.getProcessStatsLocked(app.uid, app.processName).incStartsLocked();
                 }
             }
 
@@ -8150,10 +8151,7 @@
                 }
             }
         }
-        synchronized (stats) {
-            ps = stats.getProcessStatsLocked(info.uid, proc);
-        }
-        return new ProcessRecord(ps, info, proc, uid);
+        return new ProcessRecord(stats, info, proc, uid);
     }
 
     final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
@@ -11901,6 +11899,7 @@
         boolean dumpDalvik = false;
         boolean oomOnly = false;
         boolean isCompact = false;
+        boolean localOnly = false;
         
         int opti = 0;
         while (opti < args.length) {
@@ -11919,12 +11918,15 @@
                 isCompact = true;
             } else if ("--oom".equals(opt)) {
                 oomOnly = true;
+            } else if ("--local".equals(opt)) {
+                localOnly = true;
             } else if ("-h".equals(opt)) {
                 pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]");
                 pw.println("  -a: include all available information for each process.");
                 pw.println("  -d: include dalvik details when dumping process details.");
                 pw.println("  -c: dump in a compact machine-parseable representation.");
                 pw.println("  --oom: only show processes organized by oom adj.");
+                pw.println("  --local: only collect details locally, don't call process.");
                 pw.println("If [process] is specified it can be the name or ");
                 pw.println("pid of a specific process to dump.");
                 return;
@@ -12041,14 +12043,22 @@
                     mi.dalvikPrivateDirty = (int)tmpLong[0];
                 }
                 if (dumpDetails) {
-                    try {
-                        pw.flush();
-                        thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
-                                dumpDalvik, innerArgs);
-                    } catch (RemoteException e) {
-                        if (!isCheckinRequest) {
-                            pw.println("Got RemoteException!");
+                    if (localOnly) {
+                        ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
+                                dumpDalvik, pid, r.processName, 0, 0, 0, 0, 0, 0);
+                        if (isCheckinRequest) {
+                            pw.println();
+                        }
+                    } else {
+                        try {
                             pw.flush();
+                            thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
+                                    dumpDalvik, innerArgs);
+                        } catch (RemoteException e) {
+                            if (!isCheckinRequest) {
+                                pw.println("Got RemoteException!");
+                                pw.flush();
+                            }
                         }
                     }
                 }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 809452c..0e152611 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -36,7 +36,6 @@
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
-import android.os.Trace;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.util.Objects;
 import com.android.server.Watchdog;
@@ -64,12 +63,14 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
@@ -1143,7 +1144,7 @@
                     } else if (isActivityOverHome(r)) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
                         showHomeBehindStack = true;
-                        behindFullscreen = true;
+                        behindFullscreen = !isHomeStack();
                     }
                 } else {
                     if (DEBUG_VISBILITY) Slog.v(
@@ -1716,7 +1717,7 @@
                         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                                 (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
-                                r.userId);
+                                r.userId, r.info.configChanges);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
                         }
@@ -1777,7 +1778,8 @@
             r.updateOptionsLocked(options);
             mWindowManager.addAppToken(task.mActivities.indexOf(r),
                     r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
+                    r.info.configChanges);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -1820,7 +1822,8 @@
             // because there is nothing for it to animate on top of.
             mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                     r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId);
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
+                    r.info.configChanges);
             ActivityOptions.abort(options);
         }
         if (VALIDATE_TOKENS) {
@@ -1910,26 +1913,38 @@
                 // bottom of the activity stack.  This also keeps it
                 // correctly ordered with any activities we previously
                 // moved.
+                final ThumbnailHolder newThumbHolder;
+                final TaskRecord targetTask;
                 final ActivityRecord bottom =
                         !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
-                        mTaskHistory.get(0).mActivities.get(0) : null;
+                                mTaskHistory.get(0).mActivities.get(0) : null;
                 if (bottom != null && target.taskAffinity != null
                         && target.taskAffinity.equals(bottom.task.affinity)) {
                     // If the activity currently at the bottom has the
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
-                    target.setTask(bottom.task, bottom.thumbHolder, false);
+                    targetTask = bottom.task;
+                    newThumbHolder = bottom.thumbHolder == null ? targetTask : bottom.thumbHolder;
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                             + " out to bottom task " + bottom.task);
                 } else {
-                    target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
-                            null, false), null, false);
-                    target.task.affinityIntent = target.intent;
+                    targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
+                            null, false);
+                    newThumbHolder = targetTask;
+                    targetTask.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                             + " out to new task " + target.task);
                 }
 
-                final TaskRecord targetTask = target.task;
+                if (clearWhenTaskReset) {
+                    // This is the start of a new sub-task.
+                    if (target.thumbHolder == null) {
+                        target.thumbHolder = new ThumbnailHolder();
+                    }
+                } else {
+                    target.thumbHolder = newThumbHolder;
+                }
+
                 final int targetTaskId = targetTask.taskId;
                 mWindowManager.setAppGroupId(target.appToken, targetTaskId);
 
@@ -1950,8 +1965,8 @@
                         }
                     }
                     if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
-                            + task + " adding to task=" + targetTask,
-                            new RuntimeException("here").fillInStackTrace());
+                            + task + " adding to task=" + targetTask
+                            + " Callers=" + Debug.getCallers(4));
                     if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
                             + " out to target's task " + target.task);
                     p.setTask(targetTask, curThumbHolder, false);
@@ -3145,7 +3160,9 @@
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
         if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
-            task.mOnTopOfHome = false;
+            if (task != null) {
+                task.mOnTopOfHome = false;
+            }
             return mStackSupervisor.resumeHomeActivity(null);
         }
 
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 8251364..483b4a0 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1386,17 +1386,22 @@
             launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
         }
 
+        ActivityInfo newTaskInfo = null;
+        Intent newTaskIntent = null;
         final ActivityStack sourceStack;
         if (sourceRecord != null) {
             if (sourceRecord.finishing) {
                 // If the source is finishing, we can't further count it as our source.  This
                 // is because the task it is associated with may now be empty and on its way out,
                 // so we don't want to blindly throw it in to that task.  Instead we will take
-                // the NEW_TASK flow and try to find a task for it.
+                // the NEW_TASK flow and try to find a task for it. But save the task information
+                // so it can be used when creating the new task.
                 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
                     Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                             + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
                     launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
+                    newTaskInfo = sourceRecord.info;
+                    newTaskIntent = sourceRecord.task.intent;
                 }
                 sourceRecord = null;
                 sourceStack = null;
@@ -1668,8 +1673,10 @@
             targetStack = adjustStackFocus(r);
             moveHomeStack(targetStack.isHomeStack());
             if (reuseTask == null) {
-                r.setTask(targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
-                        null, true);
+                r.setTask(targetStack.createTaskRecord(getNextTaskId(),
+                        newTaskInfo != null ? newTaskInfo : r.info,
+                        newTaskIntent != null ? newTaskIntent : intent,
+                        true), null, true);
                 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                         r.task);
             } else {
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 0dd950e..2d59678 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -419,6 +419,20 @@
         }
     }
 
+    public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
+        }
+    }
+
+    public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
+        }
+    }
+
     public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
         enforceCallingPermission();
         synchronized (mStats) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index dd3d8aa..bfb667f 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -27,6 +27,7 @@
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
@@ -814,6 +815,26 @@
                         + " to " + r.curApp + ": process crashing");
                 skip = true;
             }
+            if (!skip) {
+                boolean isAvailable = false;
+                try {
+                    isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
+                            info.activityInfo.packageName,
+                            UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
+                } catch (Exception e) {
+                    // all such failures mean we skip this receiver
+                    Slog.w(TAG, "Exception getting recipient info for "
+                            + info.activityInfo.packageName, e);
+                }
+                if (!isAvailable) {
+                    if (DEBUG_BROADCAST) {
+                        Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
+                                + " / " + info.activityInfo.applicationInfo.uid
+                                + " : package no longer available");
+                    }
+                    skip = true;
+                }
+            }
 
             if (skip) {
                 if (DEBUG_BROADCAST)  Slog.v(TAG,
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index 576adc2..423e540 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -27,7 +27,7 @@
  */
 final class ConnectionRecord {
     final AppBindRecord binding;    // The application/service binding.
-    final ActivityRecord activity;   // If non-null, the owning activity.
+    final ActivityRecord activity;  // If non-null, the owning activity.
     final IServiceConnection conn;  // The client connection.
     final int flags;                // Binding options.
     final int clientLabel;          // String resource labeling this client.
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 187cd44..217a8d61 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -46,7 +46,7 @@
  * is currently running.
  */
 final class ProcessRecord {
-    final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics
+    private final BatteryStatsImpl mBatteryStats; // where to collect runtime statistics
     final ApplicationInfo info; // all about the first app in the process
     final boolean isolated;     // true if this is a special isolated process
     final int uid;              // uid of process; may be different from 'info' if isolated
@@ -273,8 +273,8 @@
         }
         if (!keeping) {
             long wtime;
-            synchronized (batteryStats.getBatteryStats()) {
-                wtime = batteryStats.getBatteryStats().getProcessWakeTime(info.uid,
+            synchronized (mBatteryStats) {
+                wtime = mBatteryStats.getProcessWakeTime(info.uid,
                         pid, SystemClock.elapsedRealtime());
             }
             long timeUsed = wtime - lastWakeTime;
@@ -359,9 +359,9 @@
         }
     }
     
-    ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, ApplicationInfo _info,
+    ProcessRecord(BatteryStatsImpl _batteryStats, ApplicationInfo _info,
             String _processName, int _uid) {
-        batteryStats = _batteryStats;
+        mBatteryStats = _batteryStats;
         info = _info;
         isolated = _info.uid != _uid;
         uid = _uid;
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index 8d16880..e05fcda 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -750,23 +750,12 @@
                     return;
                 } else {
                     // Not an option, last argument must be a package name.
-                    try {
-                        IPackageManager pm = AppGlobals.getPackageManager();
-                        if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) {
-                            reqPackage = arg;
-                            // Include all details, since we know we are only going to
-                            // be dumping a smaller set of data.  In fact only the details
-                            // container per-package data, so that are needed to be able
-                            // to dump anything at all when filtering by package.
-                            dumpDetails = true;
-                        }
-                    } catch (RemoteException e) {
-                    }
-                    if (reqPackage == null) {
-                        pw.println("Unknown package: " + arg);
-                        dumpHelp(pw);
-                        return;
-                    }
+                    reqPackage = arg;
+                    // Include all details, since we know we are only going to
+                    // be dumping a smaller set of data.  In fact only the details
+                    // container per-package data, so that are needed to be able
+                    // to dump anything at all when filtering by package.
+                    dumpDetails = true;
                 }
             }
         }
@@ -816,13 +805,14 @@
             }
             return;
         } else if (aggregateHours != 0) {
+            pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
             dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
                     dumpDetails, dumpFullDetails, dumpAll, activeOnly);
             return;
         }
 
         boolean sepNeeded = false;
-        if (!currentOnly || isCheckin) {
+        if (dumpAll || isCheckin) {
             mWriteLock.lock();
             try {
                 ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
@@ -882,11 +872,11 @@
             }
         }
         if (!isCheckin) {
-            if (dumpAll) {
+            if (!currentOnly) {
                 if (sepNeeded) {
                     pw.println();
-                    pw.println("AGGREGATED OVER LAST 24 HOURS:");
                 }
+                pw.println("AGGREGATED OVER LAST 24 HOURS:");
                 dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
                         dumpDetails, dumpFullDetails, dumpAll, activeOnly);
                 pw.println();
@@ -901,8 +891,8 @@
                 } else {
                     if (sepNeeded) {
                         pw.println();
-                        pw.println("CURRENT STATS:");
                     }
+                    pw.println("CURRENT STATS:");
                     if (dumpDetails || dumpFullDetails) {
                         mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
                                 activeOnly);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index cc1172a..80e6e94 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -85,6 +85,7 @@
     ProcessRecord app;      // where this service is running or null.
     ProcessRecord isolatedProc; // keep track of isolated process, if requested
     ProcessStats.ServiceState tracker; // tracking service execution, may be null
+    ProcessStats.ServiceState restartTracker; // tracking service restart
     boolean delayed;        // are we waiting to start this service in the background?
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
@@ -340,6 +341,19 @@
         }
     }
 
+    public void makeRestarting(int memFactor, long now) {
+        if (restartTracker == null) {
+            if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+                restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
+                        serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name);
+            }
+            if (restartTracker == null) {
+                return;
+            }
+        }
+        restartTracker.setRestarting(true, memFactor, now);
+    }
+
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
             ProcessRecord app) {
         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index cb35ef1..023bf2b 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -660,7 +660,7 @@
         int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
-            return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId);
+            return getSyncManager().getSyncStorageEngine().getCurrentSyncsCopy(userId);
         } finally {
             restoreCallingIdentity(identityToken);
         }
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 41ef229..5ebf9ea 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -1295,21 +1295,41 @@
     }
 
     /**
-     * Return a list of the currently active syncs. Note that the returned items are the
-     * real, live active sync objects, so be careful what you do with it.
+     * Return a list of the currently active syncs. Note that the returned
+     * items are the real, live active sync objects, so be careful what you do
+     * with it.
      */
-    public List<SyncInfo> getCurrentSyncs(int userId) {
+    private List<SyncInfo> getCurrentSyncs(int userId) {
         synchronized (mAuthorities) {
-            ArrayList<SyncInfo> syncs = mCurrentSyncs.get(userId);
-            if (syncs == null) {
-                syncs = new ArrayList<SyncInfo>();
-                mCurrentSyncs.put(userId, syncs);
-            }
-            return syncs;
+            return getCurrentSyncsLocked(userId);
         }
     }
 
     /**
+     * @return a copy of the current syncs data structure. Will not return
+     * null.
+     */
+    public List<SyncInfo> getCurrentSyncsCopy(int userId) {
+        synchronized (mAuthorities) {
+            final List<SyncInfo> syncs = getCurrentSyncsLocked(userId);
+            final List<SyncInfo> syncsCopy = new ArrayList<SyncInfo>();
+            for (SyncInfo sync : syncs) {
+                syncsCopy.add(new SyncInfo(sync));
+            }
+            return syncsCopy;
+        }
+    }
+
+    private List<SyncInfo> getCurrentSyncsLocked(int userId) {
+        ArrayList<SyncInfo> syncs = mCurrentSyncs.get(userId);
+        if (syncs == null) {
+            syncs = new ArrayList<SyncInfo>();
+            mCurrentSyncs.put(userId, syncs);
+        }
+        return syncs;
+    }
+
+    /**
      * Return an array of the current sync status for all authorities.  Note
      * that the objects inside the array are the real, live status objects,
      * so be careful what you do with them.
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 249c8b0..02f26b3 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -466,6 +466,9 @@
 
     @Override // Binder call
     public void scanWifiDisplays() {
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                "Permission required to scan wifi displays");
+
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
@@ -483,13 +486,14 @@
         if (address == null) {
             throw new IllegalArgumentException("address must not be null");
         }
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                "Permission required to connect to a wifi display");
 
-        final boolean trusted = canCallerConfigureWifiDisplay();
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
                 if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestConnectLocked(address, trusted);
+                    mWifiDisplayAdapter.requestConnectLocked(address);
                 }
             }
         } finally {
@@ -499,12 +503,8 @@
 
     @Override
     public void pauseWifiDisplay() {
-        if (mContext.checkCallingPermission(
-                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
-                        != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
-                    + "permission to pause a wifi display session.");
-        }
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                "Permission required to pause a wifi display session");
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -520,12 +520,8 @@
 
     @Override
     public void resumeWifiDisplay() {
-        if (mContext.checkCallingPermission(
-                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
-                        != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY"
-                    + "permission to resume a wifi display session.");
-        }
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                "Permission required to resume a wifi display session");
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -541,6 +537,11 @@
 
     @Override // Binder call
     public void disconnectWifiDisplay() {
+        // This request does not require special permissions.
+        // Any app can request disconnection from the currently active wifi display.
+        // This exception should no longer be needed once wifi display control moves
+        // to the media router service.
+
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
@@ -558,10 +559,8 @@
         if (address == null) {
             throw new IllegalArgumentException("address must not be null");
         }
-        if (!canCallerConfigureWifiDisplay()) {
-            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
-                    + "rename a wifi display.");
-        }
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                "Permission required to rename to a wifi display");
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -580,10 +579,8 @@
         if (address == null) {
             throw new IllegalArgumentException("address must not be null");
         }
-        if (!canCallerConfigureWifiDisplay()) {
-            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission to "
-                    + "forget a wifi display.");
-        }
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                "Permission required to forget to a wifi display");
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -599,6 +596,9 @@
 
     @Override // Binder call
     public WifiDisplayStatus getWifiDisplayStatus() {
+        // This request does not require special permissions.
+        // Any app can get information about available wifi displays.
+
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (mSyncRoot) {
@@ -612,11 +612,6 @@
         }
     }
 
-    private boolean canCallerConfigureWifiDisplay() {
-        return mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
     @Override // Binder call
     public int createVirtualDisplay(IBinder appToken, String packageName,
             String name, int width, int height, int densityDpi, Surface surface, int flags) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index f7bbdf8..fdef039 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -172,19 +172,9 @@
         });
     }
 
-    public void requestConnectLocked(final String address, final boolean trusted) {
+    public void requestConnectLocked(final String address) {
         if (DEBUG) {
-            Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
-        }
-
-        if (!trusted) {
-            synchronized (getSyncRoot()) {
-                if (!isRememberedDisplayLocked(address)) {
-                    Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
-                            + "an unknown wifi display: " + address);
-                    return;
-                }
-            }
+            Slog.d(TAG, "requestConnectLocked: address=" + address);
         }
 
         getHandler().post(new Runnable() {
@@ -400,8 +390,6 @@
         mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
                 refreshRate, deviceFlags, address, surface);
         sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
-
-        scheduleUpdateNotificationLocked();
     }
 
     private void removeDisplayDeviceLocked() {
@@ -409,8 +397,6 @@
             mDisplayDevice.destroyLocked();
             sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
             mDisplayDevice = null;
-
-            scheduleUpdateNotificationLocked();
         }
     }
 
@@ -457,21 +443,24 @@
 
     // Runs on the handler.
     private void handleUpdateNotification() {
-        final boolean isConnected;
+        final int state;
+        final WifiDisplay display;
         synchronized (getSyncRoot()) {
             if (!mPendingNotificationUpdate) {
                 return;
             }
 
             mPendingNotificationUpdate = false;
-            isConnected = (mDisplayDevice != null);
+            state = mActiveDisplayState;
+            display = mActiveDisplay;
         }
 
         // Cancel the old notification if there is one.
         mNotificationManager.cancelAsUser(null,
-                R.string.wifi_display_notification_title, UserHandle.ALL);
+                R.string.wifi_display_notification_disconnect, UserHandle.ALL);
 
-        if (isConnected) {
+        if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING
+                || state == WifiDisplayStatus.DISPLAY_STATE_CONNECTED) {
             Context context = getContext();
 
             // Initialize pending intents for the notification outside of the lock because
@@ -493,20 +482,38 @@
 
             // Post the notification.
             Resources r = context.getResources();
-            Notification notification = new Notification.Builder(context)
-                    .setContentTitle(r.getString(
-                            R.string.wifi_display_notification_title))
-                    .setContentText(r.getString(
-                            R.string.wifi_display_notification_message))
-                    .setContentIntent(mSettingsPendingIntent)
-                    .setSmallIcon(R.drawable.ic_notify_wifidisplay)
-                    .setOngoing(true)
-                    .addAction(android.R.drawable.ic_menu_close_clear_cancel,
-                            r.getString(R.string.wifi_display_notification_disconnect),
-                            mDisconnectPendingIntent)
-                    .build();
+            Notification notification;
+            if (state == WifiDisplayStatus.DISPLAY_STATE_CONNECTING) {
+                notification = new Notification.Builder(context)
+                        .setContentTitle(r.getString(
+                                R.string.wifi_display_notification_connecting_title))
+                        .setContentText(r.getString(
+                                R.string.wifi_display_notification_connecting_message,
+                                display.getFriendlyDisplayName()))
+                        .setContentIntent(mSettingsPendingIntent)
+                        .setSmallIcon(R.drawable.ic_notification_cast_connecting)
+                        .setOngoing(true)
+                        .addAction(android.R.drawable.ic_menu_close_clear_cancel,
+                                r.getString(R.string.wifi_display_notification_disconnect),
+                                mDisconnectPendingIntent)
+                        .build();
+            } else {
+                notification = new Notification.Builder(context)
+                        .setContentTitle(r.getString(
+                                R.string.wifi_display_notification_connected_title))
+                        .setContentText(r.getString(
+                                R.string.wifi_display_notification_connected_message,
+                                display.getFriendlyDisplayName()))
+                        .setContentIntent(mSettingsPendingIntent)
+                        .setSmallIcon(R.drawable.ic_notification_cast_on)
+                        .setOngoing(true)
+                        .addAction(android.R.drawable.ic_menu_close_clear_cancel,
+                                r.getString(R.string.wifi_display_notification_disconnect),
+                                mDisconnectPendingIntent)
+                        .build();
+            }
             mNotificationManager.notifyAsUser(null,
-                    R.string.wifi_display_notification_title,
+                    R.string.wifi_display_notification_disconnect,
                     notification, UserHandle.ALL);
         }
     }
@@ -578,6 +585,7 @@
                     mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
                     mActiveDisplay = display;
                     scheduleStatusChangedBroadcastLocked();
+                    scheduleUpdateNotificationLocked();
                 }
             }
         }
@@ -590,6 +598,7 @@
                     mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
                     mActiveDisplay = null;
                     scheduleStatusChangedBroadcastLocked();
+                    scheduleUpdateNotificationLocked();
                 }
             }
         }
@@ -607,6 +616,7 @@
                     mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
                     mActiveDisplay = display;
                     scheduleStatusChangedBroadcastLocked();
+                    scheduleUpdateNotificationLocked();
                 }
             }
         }
@@ -629,6 +639,7 @@
                     mActiveDisplay = display;
                     renameDisplayDeviceLocked(display.getFriendlyDisplayName());
                     scheduleStatusChangedBroadcastLocked();
+                    scheduleUpdateNotificationLocked();
                 }
             }
         }
@@ -644,6 +655,7 @@
                     mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
                     mActiveDisplay = null;
                     scheduleStatusChangedBroadcastLocked();
+                    scheduleUpdateNotificationLocked();
                 }
             }
         }
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 9a4cfb7..b2939fe 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -76,7 +76,7 @@
     private static final int DEFAULT_CONTROL_PORT = 7236;
     private static final int MAX_THROUGHPUT = 50;
     private static final int CONNECTION_TIMEOUT_SECONDS = 60;
-    private static final int RTSP_TIMEOUT_SECONDS = 15;
+    private static final int RTSP_TIMEOUT_SECONDS = 30;
     private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
 
     private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index d749e6c..3145805 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -294,6 +294,7 @@
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
         filter.addDataScheme("package");
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
diff --git a/services/java/com/android/server/media/MediaRouterService.java b/services/java/com/android/server/media/MediaRouterService.java
new file mode 100644
index 0000000..a31695b
--- /dev/null
+++ b/services/java/com/android/server/media/MediaRouterService.java
@@ -0,0 +1,1423 @@
+/*
+ * Copyright (C) 2013 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.android.server.media;
+
+import com.android.internal.util.Objects;
+import com.android.server.Watchdog;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.media.AudioSystem;
+import android.media.IMediaRouterClient;
+import android.media.IMediaRouterService;
+import android.media.MediaRouter;
+import android.media.MediaRouterClientState;
+import android.media.RemoteDisplayState;
+import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Provides a mechanism for discovering media routes and manages media playback
+ * behalf of applications.
+ * <p>
+ * Currently supports discovering remote displays via remote display provider
+ * services that have been registered by applications.
+ * </p>
+ */
+public final class MediaRouterService extends IMediaRouterService.Stub
+        implements Watchdog.Monitor {
+    private static final String TAG = "MediaRouterService";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /**
+     * Timeout in milliseconds for a selected route to transition from a
+     * disconnected state to a connecting state.  If we don't observe any
+     * progress within this interval, then we will give up and unselect the route.
+     */
+    static final long CONNECTING_TIMEOUT = 5000;
+
+    /**
+     * Timeout in milliseconds for a selected route to transition from a
+     * connecting state to a connected state.  If we don't observe any
+     * progress within this interval, then we will give up and unselect the route.
+     */
+    static final long CONNECTED_TIMEOUT = 60000;
+
+    private final Context mContext;
+
+    // State guarded by mLock.
+    private final Object mLock = new Object();
+    private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
+    private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
+            new ArrayMap<IBinder, ClientRecord>();
+    private int mCurrentUserId = -1;
+
+    public MediaRouterService(Context context) {
+        mContext = context;
+        Watchdog.getInstance().addMonitor(this);
+    }
+
+    public void systemRunning() {
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) {
+                    switchUser();
+                }
+            }
+        }, filter);
+
+        switchUser();
+    }
+
+    @Override
+    public void monitor() {
+        synchronized (mLock) { /* check for deadlock */ }
+    }
+
+    // Binder call
+    @Override
+    public void registerClientAsUser(IMediaRouterClient client, String packageName, int userId) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final int uid = Binder.getCallingUid();
+        if (!validatePackageName(uid, packageName)) {
+            throw new SecurityException("packageName must match the calling uid");
+        }
+
+        final int pid = Binder.getCallingPid();
+        final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName);
+        final boolean trusted = mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) ==
+                PackageManager.PERMISSION_GRANTED;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                registerClientLocked(client, pid, packageName, resolvedUserId, trusted);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void unregisterClient(IMediaRouterClient client) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                unregisterClientLocked(client, false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public MediaRouterClientState getState(IMediaRouterClient client) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                return getStateLocked(client);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void setDiscoveryRequest(IMediaRouterClient client,
+            int routeTypes, boolean activeScan) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                setDiscoveryRequestLocked(client, routeTypes, activeScan);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    // A null routeId means that the client wants to unselect its current route.
+    // The explicit flag indicates whether the change was explicitly requested by the
+    // user or the application which may cause changes to propagate out to the rest
+    // of the system.  Should be false when the change is in response to a new globally
+    // selected route or a default selection.
+    @Override
+    public void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                setSelectedRouteLocked(client, routeId, explicit);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void requestSetVolume(IMediaRouterClient client, String routeId, int volume) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+        if (routeId == null) {
+            throw new IllegalArgumentException("routeId must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                requestSetVolumeLocked(client, routeId, volume);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+        if (routeId == null) {
+            throw new IllegalArgumentException("routeId must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                requestUpdateVolumeLocked(client, routeId, direction);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump MediaRouterService from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        pw.println("MEDIA ROUTER SERVICE (dumpsys media_router)");
+        pw.println();
+        pw.println("Global state");
+        pw.println("  mCurrentUserId=" + mCurrentUserId);
+
+        synchronized (mLock) {
+            final int count = mUserRecords.size();
+            for (int i = 0; i < count; i++) {
+                UserRecord userRecord = mUserRecords.valueAt(i);
+                pw.println();
+                userRecord.dump(pw, "");
+            }
+        }
+    }
+
+    void switchUser() {
+        synchronized (mLock) {
+            int userId = ActivityManager.getCurrentUser();
+            if (mCurrentUserId != userId) {
+                final int oldUserId = mCurrentUserId;
+                mCurrentUserId = userId; // do this first
+
+                UserRecord oldUser = mUserRecords.get(oldUserId);
+                if (oldUser != null) {
+                    oldUser.mHandler.sendEmptyMessage(UserHandler.MSG_STOP);
+                    disposeUserIfNeededLocked(oldUser); // since no longer current user
+                }
+
+                UserRecord newUser = mUserRecords.get(userId);
+                if (newUser != null) {
+                    newUser.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+                }
+            }
+        }
+    }
+
+    void clientDied(ClientRecord clientRecord) {
+        synchronized (mLock) {
+            unregisterClientLocked(clientRecord.mClient, true);
+        }
+    }
+
+    private void registerClientLocked(IMediaRouterClient client,
+            int pid, String packageName, int userId, boolean trusted) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord == null) {
+            boolean newUser = false;
+            UserRecord userRecord = mUserRecords.get(userId);
+            if (userRecord == null) {
+                userRecord = new UserRecord(userId);
+                newUser = true;
+            }
+            clientRecord = new ClientRecord(userRecord, client, pid, packageName, trusted);
+            try {
+                binder.linkToDeath(clientRecord, 0);
+            } catch (RemoteException ex) {
+                throw new RuntimeException("Media router client died prematurely.", ex);
+            }
+
+            if (newUser) {
+                mUserRecords.put(userId, userRecord);
+                initializeUserLocked(userRecord);
+            }
+
+            userRecord.mClientRecords.add(clientRecord);
+            mAllClientRecords.put(binder, clientRecord);
+            initializeClientLocked(clientRecord);
+        }
+    }
+
+    private void unregisterClientLocked(IMediaRouterClient client, boolean died) {
+        ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
+        if (clientRecord != null) {
+            UserRecord userRecord = clientRecord.mUserRecord;
+            userRecord.mClientRecords.remove(clientRecord);
+            disposeClientLocked(clientRecord, died);
+            disposeUserIfNeededLocked(userRecord); // since client removed from user
+        }
+    }
+
+    private MediaRouterClientState getStateLocked(IMediaRouterClient client) {
+        ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+        if (clientRecord != null) {
+            return clientRecord.getState();
+        }
+        return null;
+    }
+
+    private void setDiscoveryRequestLocked(IMediaRouterClient client,
+            int routeTypes, boolean activeScan) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord != null) {
+            // Only let the system discover remote display routes for now.
+            if (!clientRecord.mTrusted) {
+                routeTypes &= ~MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+            }
+
+            if (clientRecord.mRouteTypes != routeTypes
+                    || clientRecord.mActiveScan != activeScan) {
+                if (DEBUG) {
+                    Slog.d(TAG, clientRecord + ": Set discovery request, routeTypes=0x"
+                            + Integer.toHexString(routeTypes) + ", activeScan=" + activeScan);
+                }
+                clientRecord.mRouteTypes = routeTypes;
+                clientRecord.mActiveScan = activeScan;
+                clientRecord.mUserRecord.mHandler.sendEmptyMessage(
+                        UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
+            }
+        }
+    }
+
+    private void setSelectedRouteLocked(IMediaRouterClient client,
+            String routeId, boolean explicit) {
+        ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+        if (clientRecord != null) {
+            final String oldRouteId = clientRecord.mSelectedRouteId;
+            if (!Objects.equal(routeId, oldRouteId)) {
+                if (DEBUG) {
+                    Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId
+                            + ", oldRouteId=" + oldRouteId
+                            + ", explicit=" + explicit);
+                }
+
+                clientRecord.mSelectedRouteId = routeId;
+                if (explicit) {
+                    // Any app can disconnect from the globally selected route.
+                    if (oldRouteId != null) {
+                        clientRecord.mUserRecord.mHandler.obtainMessage(
+                                UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget();
+                    }
+                    // Only let the system connect to new global routes for now.
+                    // A similar check exists in the display manager for wifi display.
+                    if (routeId != null && clientRecord.mTrusted) {
+                        clientRecord.mUserRecord.mHandler.obtainMessage(
+                                UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
+                    }
+                }
+            }
+        }
+    }
+
+    private void requestSetVolumeLocked(IMediaRouterClient client,
+            String routeId, int volume) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord != null) {
+            clientRecord.mUserRecord.mHandler.obtainMessage(
+                    UserHandler.MSG_REQUEST_SET_VOLUME, volume, 0, routeId).sendToTarget();
+        }
+    }
+
+    private void requestUpdateVolumeLocked(IMediaRouterClient client,
+            String routeId, int direction) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord != null) {
+            clientRecord.mUserRecord.mHandler.obtainMessage(
+                    UserHandler.MSG_REQUEST_UPDATE_VOLUME, direction, 0, routeId).sendToTarget();
+        }
+    }
+
+    private void initializeUserLocked(UserRecord userRecord) {
+        if (DEBUG) {
+            Slog.d(TAG, userRecord + ": Initialized");
+        }
+        if (userRecord.mUserId == mCurrentUserId) {
+            userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+        }
+    }
+
+    private void disposeUserIfNeededLocked(UserRecord userRecord) {
+        // If there are no records left and the user is no longer current then go ahead
+        // and purge the user record and all of its associated state.  If the user is current
+        // then leave it alone since we might be connected to a route or want to query
+        // the same route information again soon.
+        if (userRecord.mUserId != mCurrentUserId
+                && userRecord.mClientRecords.isEmpty()) {
+            if (DEBUG) {
+                Slog.d(TAG, userRecord + ": Disposed");
+            }
+            mUserRecords.remove(userRecord.mUserId);
+            // Note: User already stopped (by switchUser) so no need to send stop message here.
+        }
+    }
+
+    private void initializeClientLocked(ClientRecord clientRecord) {
+        if (DEBUG) {
+            Slog.d(TAG, clientRecord + ": Registered");
+        }
+    }
+
+    private void disposeClientLocked(ClientRecord clientRecord, boolean died) {
+        if (DEBUG) {
+            if (died) {
+                Slog.d(TAG, clientRecord + ": Died!");
+            } else {
+                Slog.d(TAG, clientRecord + ": Unregistered");
+            }
+        }
+        if (clientRecord.mRouteTypes != 0 || clientRecord.mActiveScan) {
+            clientRecord.mUserRecord.mHandler.sendEmptyMessage(
+                    UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
+        }
+        clientRecord.dispose();
+    }
+
+    private boolean validatePackageName(int uid, String packageName) {
+        if (packageName != null) {
+            String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+            if (packageNames != null) {
+                for (String n : packageNames) {
+                    if (n.equals(packageName)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Information about a particular client of the media router.
+     * The contents of this object is guarded by mLock.
+     */
+    final class ClientRecord implements DeathRecipient {
+        public final UserRecord mUserRecord;
+        public final IMediaRouterClient mClient;
+        public final int mPid;
+        public final String mPackageName;
+        public final boolean mTrusted;
+
+        public int mRouteTypes;
+        public boolean mActiveScan;
+        public String mSelectedRouteId;
+
+        public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
+                int pid, String packageName, boolean trusted) {
+            mUserRecord = userRecord;
+            mClient = client;
+            mPid = pid;
+            mPackageName = packageName;
+            mTrusted = trusted;
+        }
+
+        public void dispose() {
+            mClient.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            clientDied(this);
+        }
+
+        MediaRouterClientState getState() {
+            return mTrusted ? mUserRecord.mTrustedState : mUserRecord.mUntrustedState;
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + this);
+
+            final String indent = prefix + "  ";
+            pw.println(indent + "mTrusted=" + mTrusted);
+            pw.println(indent + "mRouteTypes=0x" + Integer.toHexString(mRouteTypes));
+            pw.println(indent + "mActiveScan=" + mActiveScan);
+            pw.println(indent + "mSelectedRouteId=" + mSelectedRouteId);
+        }
+
+        @Override
+        public String toString() {
+            return "Client " + mPackageName + " (pid " + mPid + ")";
+        }
+    }
+
+    /**
+     * Information about a particular user.
+     * The contents of this object is guarded by mLock.
+     */
+    final class UserRecord {
+        public final int mUserId;
+        public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>();
+        public final UserHandler mHandler;
+        public MediaRouterClientState mTrustedState;
+        public MediaRouterClientState mUntrustedState;
+
+        public UserRecord(int userId) {
+            mUserId = userId;
+            mHandler = new UserHandler(MediaRouterService.this, this);
+        }
+
+        public void dump(final PrintWriter pw, String prefix) {
+            pw.println(prefix + this);
+
+            final String indent = prefix + "  ";
+            final int clientCount = mClientRecords.size();
+            if (clientCount != 0) {
+                for (int i = 0; i < clientCount; i++) {
+                    mClientRecords.get(i).dump(pw, indent);
+                }
+            } else {
+                pw.println(indent + "<no clients>");
+            }
+
+            pw.println(indent + "State");
+            pw.println(indent + "mTrustedState=" + mTrustedState);
+            pw.println(indent + "mUntrustedState=" + mUntrustedState);
+
+            if (!mHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    mHandler.dump(pw, indent);
+                }
+            }, 1000)) {
+                pw.println(indent + "<could not dump handler state>");
+            }
+         }
+
+        @Override
+        public String toString() {
+            return "User " + mUserId;
+        }
+    }
+
+    /**
+     * Media router handler
+     * <p>
+     * Since remote display providers are designed to be single-threaded by nature,
+     * this class encapsulates all of the associated functionality and exports state
+     * to the service as it evolves.
+     * </p><p>
+     * One important task of this class is to keep track of the current globally selected
+     * route id for certain routes that have global effects, such as remote displays.
+     * Global route selections override local selections made within apps.  The change
+     * is propagated to all apps so that they are all in sync.  Synchronization works
+     * both ways.  Whenever the globally selected route is explicitly unselected by any
+     * app, then it becomes unselected globally and all apps are informed.
+     * </p><p>
+     * This class is currently hardcoded to work with remote display providers but
+     * it is intended to be eventually extended to support more general route providers
+     * similar to the support library media router.
+     * </p>
+     */
+    static final class UserHandler extends Handler
+            implements RemoteDisplayProviderWatcher.Callback,
+            RemoteDisplayProviderProxy.Callback {
+        public static final int MSG_START = 1;
+        public static final int MSG_STOP = 2;
+        public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3;
+        public static final int MSG_SELECT_ROUTE = 4;
+        public static final int MSG_UNSELECT_ROUTE = 5;
+        public static final int MSG_REQUEST_SET_VOLUME = 6;
+        public static final int MSG_REQUEST_UPDATE_VOLUME = 7;
+        private static final int MSG_UPDATE_CLIENT_STATE = 8;
+        private static final int MSG_CONNECTION_TIMED_OUT = 9;
+
+        private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1;
+        private static final int TIMEOUT_REASON_CONNECTION_LOST = 2;
+        private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 3;
+        private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTED = 4;
+
+        // The relative order of these constants is important and expresses progress
+        // through the process of connecting to a route.
+        private static final int PHASE_NOT_AVAILABLE = -1;
+        private static final int PHASE_NOT_CONNECTED = 0;
+        private static final int PHASE_CONNECTING = 1;
+        private static final int PHASE_CONNECTED = 2;
+
+        private final MediaRouterService mService;
+        private final UserRecord mUserRecord;
+        private final RemoteDisplayProviderWatcher mWatcher;
+        private final ArrayList<ProviderRecord> mProviderRecords =
+                new ArrayList<ProviderRecord>();
+        private final ArrayList<IMediaRouterClient> mTempClients =
+                new ArrayList<IMediaRouterClient>();
+
+        private boolean mRunning;
+        private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE;
+        private RouteRecord mGloballySelectedRouteRecord;
+        private int mConnectionPhase = PHASE_NOT_AVAILABLE;
+        private int mConnectionTimeoutReason;
+        private long mConnectionTimeoutStartTime;
+        private boolean mClientStateUpdateScheduled;
+
+        public UserHandler(MediaRouterService service, UserRecord userRecord) {
+            super(Looper.getMainLooper(), null, true);
+            mService = service;
+            mUserRecord = userRecord;
+            mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this,
+                    this, mUserRecord.mUserId);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START: {
+                    start();
+                    break;
+                }
+                case MSG_STOP: {
+                    stop();
+                    break;
+                }
+                case MSG_UPDATE_DISCOVERY_REQUEST: {
+                    updateDiscoveryRequest();
+                    break;
+                }
+                case MSG_SELECT_ROUTE: {
+                    selectRoute((String)msg.obj);
+                    break;
+                }
+                case MSG_UNSELECT_ROUTE: {
+                    unselectRoute((String)msg.obj);
+                    break;
+                }
+                case MSG_REQUEST_SET_VOLUME: {
+                    requestSetVolume((String)msg.obj, msg.arg1);
+                    break;
+                }
+                case MSG_REQUEST_UPDATE_VOLUME: {
+                    requestUpdateVolume((String)msg.obj, msg.arg1);
+                    break;
+                }
+                case MSG_UPDATE_CLIENT_STATE: {
+                    updateClientState();
+                    break;
+                }
+                case MSG_CONNECTION_TIMED_OUT: {
+                    connectionTimedOut();
+                    break;
+                }
+            }
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + "Handler");
+
+            final String indent = prefix + "  ";
+            pw.println(indent + "mRunning=" + mRunning);
+            pw.println(indent + "mDiscoveryMode=" + mDiscoveryMode);
+            pw.println(indent + "mGloballySelectedRouteRecord=" + mGloballySelectedRouteRecord);
+            pw.println(indent + "mConnectionPhase=" + mConnectionPhase);
+            pw.println(indent + "mConnectionTimeoutReason=" + mConnectionTimeoutReason);
+            pw.println(indent + "mConnectionTimeoutStartTime=" + (mConnectionTimeoutReason != 0 ?
+                    TimeUtils.formatUptime(mConnectionTimeoutStartTime) : "<n/a>"));
+
+            mWatcher.dump(pw, prefix);
+
+            final int providerCount = mProviderRecords.size();
+            if (providerCount != 0) {
+                for (int i = 0; i < providerCount; i++) {
+                    mProviderRecords.get(i).dump(pw, prefix);
+                }
+            } else {
+                pw.println(indent + "<no providers>");
+            }
+        }
+
+        private void start() {
+            if (!mRunning) {
+                mRunning = true;
+                mWatcher.start(); // also starts all providers
+            }
+        }
+
+        private void stop() {
+            if (mRunning) {
+                mRunning = false;
+                unselectGloballySelectedRoute();
+                mWatcher.stop(); // also stops all providers
+            }
+        }
+
+        private void updateDiscoveryRequest() {
+            int routeTypes = 0;
+            boolean activeScan = false;
+            synchronized (mService.mLock) {
+                final int count = mUserRecord.mClientRecords.size();
+                for (int i = 0; i < count; i++) {
+                    ClientRecord clientRecord = mUserRecord.mClientRecords.get(i);
+                    routeTypes |= clientRecord.mRouteTypes;
+                    activeScan |= clientRecord.mActiveScan;
+                }
+            }
+
+            final int newDiscoveryMode;
+            if ((routeTypes & MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+                if (activeScan) {
+                    newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
+                } else {
+                    newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
+                }
+            } else {
+                newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE;
+            }
+
+            if (mDiscoveryMode != newDiscoveryMode) {
+                mDiscoveryMode = newDiscoveryMode;
+                final int count = mProviderRecords.size();
+                for (int i = 0; i < count; i++) {
+                    mProviderRecords.get(i).getProvider().setDiscoveryMode(mDiscoveryMode);
+                }
+            }
+        }
+
+        private void selectRoute(String routeId) {
+            if (routeId != null
+                    && (mGloballySelectedRouteRecord == null
+                            || !routeId.equals(mGloballySelectedRouteRecord.getUniqueId()))) {
+                RouteRecord routeRecord = findRouteRecord(routeId);
+                if (routeRecord != null) {
+                    unselectGloballySelectedRoute();
+
+                    Slog.i(TAG, "Selected global route:" + routeRecord);
+                    mGloballySelectedRouteRecord = routeRecord;
+                    checkGloballySelectedRouteState();
+                    routeRecord.getProvider().setSelectedDisplay(routeRecord.getDescriptorId());
+
+                    scheduleUpdateClientState();
+                }
+            }
+        }
+
+        private void unselectRoute(String routeId) {
+            if (routeId != null
+                    && mGloballySelectedRouteRecord != null
+                    && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+                unselectGloballySelectedRoute();
+            }
+        }
+
+        private void unselectGloballySelectedRoute() {
+            if (mGloballySelectedRouteRecord != null) {
+                Slog.i(TAG, "Unselected global route:" + mGloballySelectedRouteRecord);
+                mGloballySelectedRouteRecord.getProvider().setSelectedDisplay(null);
+                mGloballySelectedRouteRecord = null;
+                checkGloballySelectedRouteState();
+
+                scheduleUpdateClientState();
+            }
+        }
+
+        private void requestSetVolume(String routeId, int volume) {
+            if (mGloballySelectedRouteRecord != null
+                    && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+                mGloballySelectedRouteRecord.getProvider().setDisplayVolume(volume);
+            }
+        }
+
+        private void requestUpdateVolume(String routeId, int direction) {
+            if (mGloballySelectedRouteRecord != null
+                    && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+                mGloballySelectedRouteRecord.getProvider().adjustDisplayVolume(direction);
+            }
+        }
+
+        @Override
+        public void addProvider(RemoteDisplayProviderProxy provider) {
+            provider.setCallback(this);
+            provider.setDiscoveryMode(mDiscoveryMode);
+            provider.setSelectedDisplay(null); // just to be safe
+
+            ProviderRecord providerRecord = new ProviderRecord(provider);
+            mProviderRecords.add(providerRecord);
+            providerRecord.updateDescriptor(provider.getDisplayState());
+
+            scheduleUpdateClientState();
+        }
+
+        @Override
+        public void removeProvider(RemoteDisplayProviderProxy provider) {
+            int index = findProviderRecord(provider);
+            if (index >= 0) {
+                ProviderRecord providerRecord = mProviderRecords.remove(index);
+                providerRecord.updateDescriptor(null); // mark routes invalid
+                provider.setCallback(null);
+                provider.setDiscoveryMode(RemoteDisplayState.DISCOVERY_MODE_NONE);
+
+                checkGloballySelectedRouteState();
+                scheduleUpdateClientState();
+            }
+        }
+
+        @Override
+        public void onDisplayStateChanged(RemoteDisplayProviderProxy provider,
+                RemoteDisplayState state) {
+            updateProvider(provider, state);
+        }
+
+        private void updateProvider(RemoteDisplayProviderProxy provider,
+                RemoteDisplayState state) {
+            int index = findProviderRecord(provider);
+            if (index >= 0) {
+                ProviderRecord providerRecord = mProviderRecords.get(index);
+                if (providerRecord.updateDescriptor(state)) {
+                    checkGloballySelectedRouteState();
+                    scheduleUpdateClientState();
+                }
+            }
+        }
+
+        /**
+         * This function is called whenever the state of the globally selected route
+         * may have changed.  It checks the state and updates timeouts or unselects
+         * the route as appropriate.
+         */
+        private void checkGloballySelectedRouteState() {
+            // Unschedule timeouts when the route is unselected.
+            if (mGloballySelectedRouteRecord == null) {
+                mConnectionPhase = PHASE_NOT_AVAILABLE;
+                updateConnectionTimeout(0);
+                return;
+            }
+
+            // Ensure that the route is still present and enabled.
+            if (!mGloballySelectedRouteRecord.isValid()
+                    || !mGloballySelectedRouteRecord.isEnabled()) {
+                updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE);
+                return;
+            }
+
+            // Make sure we haven't lost our connection.
+            final int oldPhase = mConnectionPhase;
+            mConnectionPhase = getConnectionPhase(mGloballySelectedRouteRecord.getStatus());
+            if (oldPhase >= PHASE_CONNECTING && mConnectionPhase < PHASE_CONNECTING) {
+                updateConnectionTimeout(TIMEOUT_REASON_CONNECTION_LOST);
+                return;
+            }
+
+            // Check the route status.
+            switch (mConnectionPhase) {
+                case PHASE_CONNECTED:
+                    if (oldPhase != PHASE_CONNECTED) {
+                        Slog.i(TAG, "Connected to global route: "
+                                + mGloballySelectedRouteRecord);
+                    }
+                    updateConnectionTimeout(0);
+                    break;
+                case PHASE_CONNECTING:
+                    if (oldPhase != PHASE_CONNECTING) {
+                        Slog.i(TAG, "Connecting to global route: "
+                                + mGloballySelectedRouteRecord);
+                    }
+                    updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTED);
+                    break;
+                case PHASE_NOT_CONNECTED:
+                    updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTING);
+                    break;
+                case PHASE_NOT_AVAILABLE:
+                default:
+                    updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE);
+                    break;
+            }
+        }
+
+        private void updateConnectionTimeout(int reason) {
+            if (reason != mConnectionTimeoutReason) {
+                if (mConnectionTimeoutReason != 0) {
+                    removeMessages(MSG_CONNECTION_TIMED_OUT);
+                }
+                mConnectionTimeoutReason = reason;
+                mConnectionTimeoutStartTime = SystemClock.uptimeMillis();
+                switch (reason) {
+                    case TIMEOUT_REASON_NOT_AVAILABLE:
+                    case TIMEOUT_REASON_CONNECTION_LOST:
+                        // Route became unavailable or connection lost.
+                        // Unselect it immediately.
+                        sendEmptyMessage(MSG_CONNECTION_TIMED_OUT);
+                        break;
+                    case TIMEOUT_REASON_WAITING_FOR_CONNECTING:
+                        // Waiting for route to start connecting.
+                        sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTING_TIMEOUT);
+                        break;
+                    case TIMEOUT_REASON_WAITING_FOR_CONNECTED:
+                        // Waiting for route to complete connection.
+                        sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTED_TIMEOUT);
+                        break;
+                }
+            }
+        }
+
+        private void connectionTimedOut() {
+            if (mConnectionTimeoutReason == 0 || mGloballySelectedRouteRecord == null) {
+                // Shouldn't get here.  There must be a bug somewhere.
+                Log.wtf(TAG, "Handled connection timeout for no reason.");
+                return;
+            }
+
+            switch (mConnectionTimeoutReason) {
+                case TIMEOUT_REASON_NOT_AVAILABLE:
+                    Slog.i(TAG, "Global route no longer available: "
+                            + mGloballySelectedRouteRecord);
+                    break;
+                case TIMEOUT_REASON_CONNECTION_LOST:
+                    Slog.i(TAG, "Global route connection lost: "
+                            + mGloballySelectedRouteRecord);
+                    break;
+                case TIMEOUT_REASON_WAITING_FOR_CONNECTING:
+                    Slog.i(TAG, "Global route timed out while waiting for "
+                            + "connection attempt to begin after "
+                            + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime)
+                            + " ms: " + mGloballySelectedRouteRecord);
+                    break;
+                case TIMEOUT_REASON_WAITING_FOR_CONNECTED:
+                    Slog.i(TAG, "Global route timed out while connecting after "
+                            + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime)
+                            + " ms: " + mGloballySelectedRouteRecord);
+                    break;
+            }
+            mConnectionTimeoutReason = 0;
+
+            unselectGloballySelectedRoute();
+        }
+
+        private void scheduleUpdateClientState() {
+            if (!mClientStateUpdateScheduled) {
+                mClientStateUpdateScheduled = true;
+                sendEmptyMessage(MSG_UPDATE_CLIENT_STATE);
+            }
+        }
+
+        private void updateClientState() {
+            mClientStateUpdateScheduled = false;
+
+            final String globallySelectedRouteId = mGloballySelectedRouteRecord != null ?
+                    mGloballySelectedRouteRecord.getUniqueId() : null;
+
+            // Build a new client state for trusted clients.
+            MediaRouterClientState trustedState = new MediaRouterClientState();
+            trustedState.globallySelectedRouteId = globallySelectedRouteId;
+            final int providerCount = mProviderRecords.size();
+            for (int i = 0; i < providerCount; i++) {
+                mProviderRecords.get(i).appendClientState(trustedState);
+            }
+
+            // Build a new client state for untrusted clients that can only see
+            // the currently selected route.
+            MediaRouterClientState untrustedState = new MediaRouterClientState();
+            untrustedState.globallySelectedRouteId = globallySelectedRouteId;
+            if (globallySelectedRouteId != null) {
+                untrustedState.routes.add(trustedState.getRoute(globallySelectedRouteId));
+            }
+
+            try {
+                synchronized (mService.mLock) {
+                    // Update the UserRecord.
+                    mUserRecord.mTrustedState = trustedState;
+                    mUserRecord.mUntrustedState = untrustedState;
+
+                    // Collect all clients.
+                    final int count = mUserRecord.mClientRecords.size();
+                    for (int i = 0; i < count; i++) {
+                        mTempClients.add(mUserRecord.mClientRecords.get(i).mClient);
+                    }
+                }
+
+                // Notify all clients (outside of the lock).
+                final int count = mTempClients.size();
+                for (int i = 0; i < count; i++) {
+                    try {
+                        mTempClients.get(i).onStateChanged();
+                    } catch (RemoteException ex) {
+                        // ignore errors, client probably died
+                    }
+                }
+            } finally {
+                // Clear the list in preparation for the next time.
+                mTempClients.clear();
+            }
+        }
+
+        private int findProviderRecord(RemoteDisplayProviderProxy provider) {
+            final int count = mProviderRecords.size();
+            for (int i = 0; i < count; i++) {
+                ProviderRecord record = mProviderRecords.get(i);
+                if (record.getProvider() == provider) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        private RouteRecord findRouteRecord(String uniqueId) {
+            final int count = mProviderRecords.size();
+            for (int i = 0; i < count; i++) {
+                RouteRecord record = mProviderRecords.get(i).findRouteByUniqueId(uniqueId);
+                if (record != null) {
+                    return record;
+                }
+            }
+            return null;
+        }
+
+        private static int getConnectionPhase(int status) {
+            switch (status) {
+                case MediaRouter.RouteInfo.STATUS_NONE:
+                case MediaRouter.RouteInfo.STATUS_CONNECTED:
+                    return PHASE_CONNECTED;
+                case MediaRouter.RouteInfo.STATUS_CONNECTING:
+                    return PHASE_CONNECTING;
+                case MediaRouter.RouteInfo.STATUS_SCANNING:
+                case MediaRouter.RouteInfo.STATUS_AVAILABLE:
+                    return PHASE_NOT_CONNECTED;
+                case MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE:
+                case MediaRouter.RouteInfo.STATUS_IN_USE:
+                default:
+                    return PHASE_NOT_AVAILABLE;
+            }
+        }
+
+        static final class ProviderRecord {
+            private final RemoteDisplayProviderProxy mProvider;
+            private final String mUniquePrefix;
+            private final ArrayList<RouteRecord> mRoutes = new ArrayList<RouteRecord>();
+            private RemoteDisplayState mDescriptor;
+
+            public ProviderRecord(RemoteDisplayProviderProxy provider) {
+                mProvider = provider;
+                mUniquePrefix = provider.getFlattenedComponentName() + ":";
+            }
+
+            public RemoteDisplayProviderProxy getProvider() {
+                return mProvider;
+            }
+
+            public String getUniquePrefix() {
+                return mUniquePrefix;
+            }
+
+            public boolean updateDescriptor(RemoteDisplayState descriptor) {
+                boolean changed = false;
+                if (mDescriptor != descriptor) {
+                    mDescriptor = descriptor;
+
+                    // Update all existing routes and reorder them to match
+                    // the order of their descriptors.
+                    int targetIndex = 0;
+                    if (descriptor != null) {
+                        if (descriptor.isValid()) {
+                            final List<RemoteDisplayInfo> routeDescriptors = descriptor.displays;
+                            final int routeCount = routeDescriptors.size();
+                            for (int i = 0; i < routeCount; i++) {
+                                final RemoteDisplayInfo routeDescriptor =
+                                        routeDescriptors.get(i);
+                                final String descriptorId = routeDescriptor.id;
+                                final int sourceIndex = findRouteByDescriptorId(descriptorId);
+                                if (sourceIndex < 0) {
+                                    // Add the route to the provider.
+                                    String uniqueId = assignRouteUniqueId(descriptorId);
+                                    RouteRecord route =
+                                            new RouteRecord(this, descriptorId, uniqueId);
+                                    mRoutes.add(targetIndex++, route);
+                                    route.updateDescriptor(routeDescriptor);
+                                    changed = true;
+                                } else if (sourceIndex < targetIndex) {
+                                    // Ignore route with duplicate id.
+                                    Slog.w(TAG, "Ignoring route descriptor with duplicate id: "
+                                            + routeDescriptor);
+                                } else {
+                                    // Reorder existing route within the list.
+                                    RouteRecord route = mRoutes.get(sourceIndex);
+                                    Collections.swap(mRoutes, sourceIndex, targetIndex++);
+                                    changed |= route.updateDescriptor(routeDescriptor);
+                                }
+                            }
+                        } else {
+                            Slog.w(TAG, "Ignoring invalid descriptor from media route provider: "
+                                    + mProvider.getFlattenedComponentName());
+                        }
+                    }
+
+                    // Dispose all remaining routes that do not have matching descriptors.
+                    for (int i = mRoutes.size() - 1; i >= targetIndex; i--) {
+                        RouteRecord route = mRoutes.remove(i);
+                        route.updateDescriptor(null); // mark route invalid
+                        changed = true;
+                    }
+                }
+                return changed;
+            }
+
+            public void appendClientState(MediaRouterClientState state) {
+                final int routeCount = mRoutes.size();
+                for (int i = 0; i < routeCount; i++) {
+                    state.routes.add(mRoutes.get(i).getInfo());
+                }
+            }
+
+            public RouteRecord findRouteByUniqueId(String uniqueId) {
+                final int routeCount = mRoutes.size();
+                for (int i = 0; i < routeCount; i++) {
+                    RouteRecord route = mRoutes.get(i);
+                    if (route.getUniqueId().equals(uniqueId)) {
+                        return route;
+                    }
+                }
+                return null;
+            }
+
+            private int findRouteByDescriptorId(String descriptorId) {
+                final int routeCount = mRoutes.size();
+                for (int i = 0; i < routeCount; i++) {
+                    RouteRecord route = mRoutes.get(i);
+                    if (route.getDescriptorId().equals(descriptorId)) {
+                        return i;
+                    }
+                }
+                return -1;
+            }
+
+            public void dump(PrintWriter pw, String prefix) {
+                pw.println(prefix + this);
+
+                final String indent = prefix + "  ";
+                mProvider.dump(pw, indent);
+
+                final int routeCount = mRoutes.size();
+                if (routeCount != 0) {
+                    for (int i = 0; i < routeCount; i++) {
+                        mRoutes.get(i).dump(pw, indent);
+                    }
+                } else {
+                    pw.println(indent + "<no routes>");
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "Provider " + mProvider.getFlattenedComponentName();
+            }
+
+            private String assignRouteUniqueId(String descriptorId) {
+                return mUniquePrefix + descriptorId;
+            }
+        }
+
+        static final class RouteRecord {
+            private final ProviderRecord mProviderRecord;
+            private final String mDescriptorId;
+            private final MediaRouterClientState.RouteInfo mMutableInfo;
+            private MediaRouterClientState.RouteInfo mImmutableInfo;
+            private RemoteDisplayInfo mDescriptor;
+
+            public RouteRecord(ProviderRecord providerRecord,
+                    String descriptorId, String uniqueId) {
+                mProviderRecord = providerRecord;
+                mDescriptorId = descriptorId;
+                mMutableInfo = new MediaRouterClientState.RouteInfo(uniqueId);
+            }
+
+            public RemoteDisplayProviderProxy getProvider() {
+                return mProviderRecord.getProvider();
+            }
+
+            public ProviderRecord getProviderRecord() {
+                return mProviderRecord;
+            }
+
+            public String getDescriptorId() {
+                return mDescriptorId;
+            }
+
+            public String getUniqueId() {
+                return mMutableInfo.id;
+            }
+
+            public MediaRouterClientState.RouteInfo getInfo() {
+                if (mImmutableInfo == null) {
+                    mImmutableInfo = new MediaRouterClientState.RouteInfo(mMutableInfo);
+                }
+                return mImmutableInfo;
+            }
+
+            public boolean isValid() {
+                return mDescriptor != null;
+            }
+
+            public boolean isEnabled() {
+                return mMutableInfo.enabled;
+            }
+
+            public int getStatus() {
+                return mMutableInfo.statusCode;
+            }
+
+            public boolean updateDescriptor(RemoteDisplayInfo descriptor) {
+                boolean changed = false;
+                if (mDescriptor != descriptor) {
+                    mDescriptor = descriptor;
+                    if (descriptor != null) {
+                        final String name = computeName(descriptor);
+                        if (!Objects.equal(mMutableInfo.name, name)) {
+                            mMutableInfo.name = name;
+                            changed = true;
+                        }
+                        final String description = computeDescription(descriptor);
+                        if (!Objects.equal(mMutableInfo.description, description)) {
+                            mMutableInfo.description = description;
+                            changed = true;
+                        }
+                        final int supportedTypes = computeSupportedTypes(descriptor);
+                        if (mMutableInfo.supportedTypes != supportedTypes) {
+                            mMutableInfo.supportedTypes = supportedTypes;
+                            changed = true;
+                        }
+                        final boolean enabled = computeEnabled(descriptor);
+                        if (mMutableInfo.enabled != enabled) {
+                            mMutableInfo.enabled = enabled;
+                            changed = true;
+                        }
+                        final int statusCode = computeStatusCode(descriptor);
+                        if (mMutableInfo.statusCode != statusCode) {
+                            mMutableInfo.statusCode = statusCode;
+                            changed = true;
+                        }
+                        final int playbackType = computePlaybackType(descriptor);
+                        if (mMutableInfo.playbackType != playbackType) {
+                            mMutableInfo.playbackType = playbackType;
+                            changed = true;
+                        }
+                        final int playbackStream = computePlaybackStream(descriptor);
+                        if (mMutableInfo.playbackStream != playbackStream) {
+                            mMutableInfo.playbackStream = playbackStream;
+                            changed = true;
+                        }
+                        final int volume = computeVolume(descriptor);
+                        if (mMutableInfo.volume != volume) {
+                            mMutableInfo.volume = volume;
+                            changed = true;
+                        }
+                        final int volumeMax = computeVolumeMax(descriptor);
+                        if (mMutableInfo.volumeMax != volumeMax) {
+                            mMutableInfo.volumeMax = volumeMax;
+                            changed = true;
+                        }
+                        final int volumeHandling = computeVolumeHandling(descriptor);
+                        if (mMutableInfo.volumeHandling != volumeHandling) {
+                            mMutableInfo.volumeHandling = volumeHandling;
+                            changed = true;
+                        }
+                        final int presentationDisplayId = computePresentationDisplayId(descriptor);
+                        if (mMutableInfo.presentationDisplayId != presentationDisplayId) {
+                            mMutableInfo.presentationDisplayId = presentationDisplayId;
+                            changed = true;
+                        }
+                    }
+                }
+                if (changed) {
+                    mImmutableInfo = null;
+                }
+                return changed;
+            }
+
+            public void dump(PrintWriter pw, String prefix) {
+                pw.println(prefix + this);
+
+                final String indent = prefix + "  ";
+                pw.println(indent + "mMutableInfo=" + mMutableInfo);
+                pw.println(indent + "mDescriptorId=" + mDescriptorId);
+                pw.println(indent + "mDescriptor=" + mDescriptor);
+            }
+
+            @Override
+            public String toString() {
+                return "Route " + mMutableInfo.name + " (" + mMutableInfo.id + ")";
+            }
+
+            private static String computeName(RemoteDisplayInfo descriptor) {
+                // Note that isValid() already ensures the name is non-empty.
+                return descriptor.name;
+            }
+
+            private static String computeDescription(RemoteDisplayInfo descriptor) {
+                final String description = descriptor.description;
+                return TextUtils.isEmpty(description) ? null : description;
+            }
+
+            private static int computeSupportedTypes(RemoteDisplayInfo descriptor) {
+                return MediaRouter.ROUTE_TYPE_LIVE_AUDIO
+                        | MediaRouter.ROUTE_TYPE_LIVE_VIDEO
+                        | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+            }
+
+            private static boolean computeEnabled(RemoteDisplayInfo descriptor) {
+                switch (descriptor.status) {
+                    case RemoteDisplayInfo.STATUS_CONNECTED:
+                    case RemoteDisplayInfo.STATUS_CONNECTING:
+                    case RemoteDisplayInfo.STATUS_AVAILABLE:
+                        return true;
+                    default:
+                        return false;
+                }
+            }
+
+            private static int computeStatusCode(RemoteDisplayInfo descriptor) {
+                switch (descriptor.status) {
+                    case RemoteDisplayInfo.STATUS_NOT_AVAILABLE:
+                        return MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE;
+                    case RemoteDisplayInfo.STATUS_AVAILABLE:
+                        return MediaRouter.RouteInfo.STATUS_AVAILABLE;
+                    case RemoteDisplayInfo.STATUS_IN_USE:
+                        return MediaRouter.RouteInfo.STATUS_IN_USE;
+                    case RemoteDisplayInfo.STATUS_CONNECTING:
+                        return MediaRouter.RouteInfo.STATUS_CONNECTING;
+                    case RemoteDisplayInfo.STATUS_CONNECTED:
+                        return MediaRouter.RouteInfo.STATUS_CONNECTED;
+                    default:
+                        return MediaRouter.RouteInfo.STATUS_NONE;
+                }
+            }
+
+            private static int computePlaybackType(RemoteDisplayInfo descriptor) {
+                return MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+            }
+
+            private static int computePlaybackStream(RemoteDisplayInfo descriptor) {
+                return AudioSystem.STREAM_MUSIC;
+            }
+
+            private static int computeVolume(RemoteDisplayInfo descriptor) {
+                final int volume = descriptor.volume;
+                final int volumeMax = descriptor.volumeMax;
+                if (volume < 0) {
+                    return 0;
+                } else if (volume > volumeMax) {
+                    return volumeMax;
+                }
+                return volume;
+            }
+
+            private static int computeVolumeMax(RemoteDisplayInfo descriptor) {
+                final int volumeMax = descriptor.volumeMax;
+                return volumeMax > 0 ? volumeMax : 0;
+            }
+
+            private static int computeVolumeHandling(RemoteDisplayInfo descriptor) {
+                final int volumeHandling = descriptor.volumeHandling;
+                switch (volumeHandling) {
+                    case RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE:
+                        return MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+                    case RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED:
+                    default:
+                        return MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+                }
+            }
+
+            private static int computePresentationDisplayId(RemoteDisplayInfo descriptor) {
+                // The MediaRouter class validates that the id corresponds to an extant
+                // presentation display.  So all we do here is canonicalize the null case.
+                final int displayId = descriptor.presentationDisplayId;
+                return displayId < 0 ? -1 : displayId;
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
new file mode 100644
index 0000000..b248ee0
--- /dev/null
+++ b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2013 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.android.server.media;
+
+import com.android.internal.util.Objects;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.IRemoteDisplayCallback;
+import android.media.IRemoteDisplayProvider;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.IBinder.DeathRecipient;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * Maintains a connection to a particular remote display provider service.
+ */
+final class RemoteDisplayProviderProxy implements ServiceConnection {
+    private static final String TAG = "RemoteDisplayProvider";  // max. 23 chars
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private final ComponentName mComponentName;
+    private final int mUserId;
+    private final Handler mHandler;
+
+    private Callback mDisplayStateCallback;
+
+    // Connection state
+    private boolean mRunning;
+    private boolean mBound;
+    private Connection mActiveConnection;
+    private boolean mConnectionReady;
+
+    // Logical state
+    private int mDiscoveryMode;
+    private String mSelectedDisplayId;
+    private RemoteDisplayState mDisplayState;
+    private boolean mScheduledDisplayStateChangedCallback;
+
+    public RemoteDisplayProviderProxy(Context context, ComponentName componentName,
+            int userId) {
+        mContext = context;
+        mComponentName = componentName;
+        mUserId = userId;
+        mHandler = new Handler();
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "Proxy");
+        pw.println(prefix + "  mUserId=" + mUserId);
+        pw.println(prefix + "  mRunning=" + mRunning);
+        pw.println(prefix + "  mBound=" + mBound);
+        pw.println(prefix + "  mActiveConnection=" + mActiveConnection);
+        pw.println(prefix + "  mConnectionReady=" + mConnectionReady);
+        pw.println(prefix + "  mDiscoveryMode=" + mDiscoveryMode);
+        pw.println(prefix + "  mSelectedDisplayId=" + mSelectedDisplayId);
+        pw.println(prefix + "  mDisplayState=" + mDisplayState);
+    }
+
+    public void setCallback(Callback callback) {
+        mDisplayStateCallback = callback;
+    }
+
+    public RemoteDisplayState getDisplayState() {
+        return mDisplayState;
+    }
+
+    public void setDiscoveryMode(int mode) {
+        if (mDiscoveryMode != mode) {
+            mDiscoveryMode = mode;
+            if (mConnectionReady) {
+                mActiveConnection.setDiscoveryMode(mode);
+            }
+            updateBinding();
+        }
+    }
+
+    public void setSelectedDisplay(String id) {
+        if (!Objects.equal(mSelectedDisplayId, id)) {
+            if (mConnectionReady && mSelectedDisplayId != null) {
+                mActiveConnection.disconnect(mSelectedDisplayId);
+            }
+            mSelectedDisplayId = id;
+            if (mConnectionReady && id != null) {
+                mActiveConnection.connect(id);
+            }
+            updateBinding();
+        }
+    }
+
+    public void setDisplayVolume(int volume) {
+        if (mConnectionReady && mSelectedDisplayId != null) {
+            mActiveConnection.setVolume(mSelectedDisplayId, volume);
+        }
+    }
+
+    public void adjustDisplayVolume(int delta) {
+        if (mConnectionReady && mSelectedDisplayId != null) {
+            mActiveConnection.adjustVolume(mSelectedDisplayId, delta);
+        }
+    }
+
+    public boolean hasComponentName(String packageName, String className) {
+        return mComponentName.getPackageName().equals(packageName)
+                && mComponentName.getClassName().equals(className);
+    }
+
+    public String getFlattenedComponentName() {
+        return mComponentName.flattenToShortString();
+    }
+
+    public void start() {
+        if (!mRunning) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Starting");
+            }
+
+            mRunning = true;
+            updateBinding();
+        }
+    }
+
+    public void stop() {
+        if (mRunning) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Stopping");
+            }
+
+            mRunning = false;
+            updateBinding();
+        }
+    }
+
+    public void rebindIfDisconnected() {
+        if (mActiveConnection == null && shouldBind()) {
+            unbind();
+            bind();
+        }
+    }
+
+    private void updateBinding() {
+        if (shouldBind()) {
+            bind();
+        } else {
+            unbind();
+        }
+    }
+
+    private boolean shouldBind() {
+        if (mRunning) {
+            // Bind whenever there is a discovery request or selected display.
+            if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE
+                    || mSelectedDisplayId != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void bind() {
+        if (!mBound) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Binding");
+            }
+
+            Intent service = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
+            service.setComponent(mComponentName);
+            try {
+                mBound = mContext.bindServiceAsUser(service, this, Context.BIND_AUTO_CREATE,
+                        new UserHandle(mUserId));
+                if (!mBound && DEBUG) {
+                    Slog.d(TAG, this + ": Bind failed");
+                }
+            } catch (SecurityException ex) {
+                if (DEBUG) {
+                    Slog.d(TAG, this + ": Bind failed", ex);
+                }
+            }
+        }
+    }
+
+    private void unbind() {
+        if (mBound) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Unbinding");
+            }
+
+            mBound = false;
+            disconnect();
+            mContext.unbindService(this);
+        }
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        if (DEBUG) {
+            Slog.d(TAG, this + ": Connected");
+        }
+
+        if (mBound) {
+            disconnect();
+
+            IRemoteDisplayProvider provider = IRemoteDisplayProvider.Stub.asInterface(service);
+            if (provider != null) {
+                Connection connection = new Connection(provider);
+                if (connection.register()) {
+                    mActiveConnection = connection;
+                } else {
+                    if (DEBUG) {
+                        Slog.d(TAG, this + ": Registration failed");
+                    }
+                }
+            } else {
+                Slog.e(TAG, this + ": Service returned invalid remote display provider binder");
+            }
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        if (DEBUG) {
+            Slog.d(TAG, this + ": Service disconnected");
+        }
+        disconnect();
+    }
+
+    private void onConnectionReady(Connection connection) {
+        if (mActiveConnection == connection) {
+            mConnectionReady = true;
+
+            if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE) {
+                mActiveConnection.setDiscoveryMode(mDiscoveryMode);
+            }
+            if (mSelectedDisplayId != null) {
+                mActiveConnection.connect(mSelectedDisplayId);
+            }
+        }
+    }
+
+    private void onConnectionDied(Connection connection) {
+        if (mActiveConnection == connection) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Service connection died");
+            }
+            disconnect();
+        }
+    }
+
+    private void onDisplayStateChanged(Connection connection, RemoteDisplayState state) {
+        if (mActiveConnection == connection) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": State changed, state=" + state);
+            }
+            setDisplayState(state);
+        }
+    }
+
+    private void disconnect() {
+        if (mActiveConnection != null) {
+            if (mSelectedDisplayId != null) {
+                mActiveConnection.disconnect(mSelectedDisplayId);
+            }
+            mConnectionReady = false;
+            mActiveConnection.dispose();
+            mActiveConnection = null;
+            setDisplayState(null);
+        }
+    }
+
+    private void setDisplayState(RemoteDisplayState state) {
+        if (!Objects.equal(mDisplayState, state)) {
+            mDisplayState = state;
+            if (!mScheduledDisplayStateChangedCallback) {
+                mScheduledDisplayStateChangedCallback = true;
+                mHandler.post(mDisplayStateChanged);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Service connection " + mComponentName.flattenToShortString();
+    }
+
+    private final Runnable mDisplayStateChanged = new Runnable() {
+        @Override
+        public void run() {
+            mScheduledDisplayStateChangedCallback = false;
+            if (mDisplayStateCallback != null) {
+                mDisplayStateCallback.onDisplayStateChanged(
+                        RemoteDisplayProviderProxy.this, mDisplayState);
+            }
+        }
+    };
+
+    public interface Callback {
+        void onDisplayStateChanged(RemoteDisplayProviderProxy provider, RemoteDisplayState state);
+    }
+
+    private final class Connection implements DeathRecipient {
+        private final IRemoteDisplayProvider mProvider;
+        private final ProviderCallback mCallback;
+
+        public Connection(IRemoteDisplayProvider provider) {
+            mProvider = provider;
+            mCallback = new ProviderCallback(this);
+        }
+
+        public boolean register() {
+            try {
+                mProvider.asBinder().linkToDeath(this, 0);
+                mProvider.setCallback(mCallback);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onConnectionReady(Connection.this);
+                    }
+                });
+                return true;
+            } catch (RemoteException ex) {
+                binderDied();
+            }
+            return false;
+        }
+
+        public void dispose() {
+            mProvider.asBinder().unlinkToDeath(this, 0);
+            mCallback.dispose();
+        }
+
+        public void setDiscoveryMode(int mode) {
+            try {
+                mProvider.setDiscoveryMode(mode);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
+            }
+        }
+
+        public void connect(String id) {
+            try {
+                mProvider.connect(id);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to connect to display.", ex);
+            }
+        }
+
+        public void disconnect(String id) {
+            try {
+                mProvider.disconnect(id);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to disconnect from display.", ex);
+            }
+        }
+
+        public void setVolume(String id, int volume) {
+            try {
+                mProvider.setVolume(id, volume);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to set display volume.", ex);
+            }
+        }
+
+        public void adjustVolume(String id, int volume) {
+            try {
+                mProvider.adjustVolume(id, volume);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to adjust display volume.", ex);
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onConnectionDied(Connection.this);
+                }
+            });
+        }
+
+        void postStateChanged(final RemoteDisplayState state) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onDisplayStateChanged(Connection.this, state);
+                }
+            });
+        }
+    }
+
+    /**
+     * Receives callbacks from the service.
+     * <p>
+     * This inner class is static and only retains a weak reference to the connection
+     * to prevent the client from being leaked in case the service is holding an
+     * active reference to the client's callback.
+     * </p>
+     */
+    private static final class ProviderCallback extends IRemoteDisplayCallback.Stub {
+        private final WeakReference<Connection> mConnectionRef;
+
+        public ProviderCallback(Connection connection) {
+            mConnectionRef = new WeakReference<Connection>(connection);
+        }
+
+        public void dispose() {
+            mConnectionRef.clear();
+        }
+
+        @Override
+        public void onStateChanged(RemoteDisplayState state) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.postStateChanged(state);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
new file mode 100644
index 0000000..6a5f563
--- /dev/null
+++ b/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2013 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.android.server.media;
+
+import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Watches for remote display provider services to be installed.
+ * Adds a provider to the media router for each registered service.
+ *
+ * @see RemoteDisplayProviderProxy
+ */
+public final class RemoteDisplayProviderWatcher {
+    private static final String TAG = "RemoteDisplayProvider";  // max. 23 chars
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private final Callback mCallback;
+    private final Handler mHandler;
+    private final int mUserId;
+    private final PackageManager mPackageManager;
+
+    private final ArrayList<RemoteDisplayProviderProxy> mProviders =
+            new ArrayList<RemoteDisplayProviderProxy>();
+    private boolean mRunning;
+
+    public RemoteDisplayProviderWatcher(Context context,
+            Callback callback, Handler handler, int userId) {
+        mContext = context;
+        mCallback = callback;
+        mHandler = handler;
+        mUserId = userId;
+        mPackageManager = context.getPackageManager();
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "Watcher");
+        pw.println(prefix + "  mUserId=" + mUserId);
+        pw.println(prefix + "  mRunning=" + mRunning);
+        pw.println(prefix + "  mProviders.size()=" + mProviders.size());
+    }
+
+    public void start() {
+        if (!mRunning) {
+            mRunning = true;
+
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+            filter.addDataScheme("package");
+            mContext.registerReceiverAsUser(mScanPackagesReceiver,
+                    new UserHandle(mUserId), filter, null, mHandler);
+
+            // Scan packages.
+            // Also has the side-effect of restarting providers if needed.
+            mHandler.post(mScanPackagesRunnable);
+        }
+    }
+
+    public void stop() {
+        if (mRunning) {
+            mRunning = false;
+
+            mContext.unregisterReceiver(mScanPackagesReceiver);
+            mHandler.removeCallbacks(mScanPackagesRunnable);
+
+            // Stop all providers.
+            for (int i = mProviders.size() - 1; i >= 0; i--) {
+                mProviders.get(i).stop();
+            }
+        }
+    }
+
+    private void scanPackages() {
+        if (!mRunning) {
+            return;
+        }
+
+        // Add providers for all new services.
+        // Reorder the list so that providers left at the end will be the ones to remove.
+        int targetIndex = 0;
+        Intent intent = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
+        for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
+                intent, 0, mUserId)) {
+            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+            if (serviceInfo != null && verifyServiceTrusted(serviceInfo)) {
+                int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
+                if (sourceIndex < 0) {
+                    RemoteDisplayProviderProxy provider =
+                            new RemoteDisplayProviderProxy(mContext,
+                            new ComponentName(serviceInfo.packageName, serviceInfo.name),
+                            mUserId);
+                    provider.start();
+                    mProviders.add(targetIndex++, provider);
+                    mCallback.addProvider(provider);
+                } else if (sourceIndex >= targetIndex) {
+                    RemoteDisplayProviderProxy provider = mProviders.get(sourceIndex);
+                    provider.start(); // restart the provider if needed
+                    provider.rebindIfDisconnected();
+                    Collections.swap(mProviders, sourceIndex, targetIndex++);
+                }
+            }
+        }
+
+        // Remove providers for missing services.
+        if (targetIndex < mProviders.size()) {
+            for (int i = mProviders.size() - 1; i >= targetIndex; i--) {
+                RemoteDisplayProviderProxy provider = mProviders.get(i);
+                mCallback.removeProvider(provider);
+                mProviders.remove(provider);
+                provider.stop();
+            }
+        }
+    }
+
+    private boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
+        if (serviceInfo.permission == null || !serviceInfo.permission.equals(
+                Manifest.permission.BIND_REMOTE_DISPLAY)) {
+            // If the service does not require this permission then any app could
+            // potentially bind to it and cause the remote display service to
+            // misbehave.  So we only want to trust providers that require the
+            // correct permissions.
+            Slog.w(TAG, "Ignoring remote display provider service because it did not "
+                    + "require the BIND_REMOTE_DISPLAY permission in its manifest: "
+                    + serviceInfo.packageName + "/" + serviceInfo.name);
+            return false;
+        }
+        if (!hasCaptureVideoPermission(serviceInfo.packageName)) {
+            // If the service does not have permission to capture video then it
+            // isn't going to be terribly useful as a remote display, is it?
+            // Kind of makes you wonder what it's doing there in the first place.
+            Slog.w(TAG, "Ignoring remote display provider service because it does not "
+                    + "have the CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT "
+                    + "permission: " + serviceInfo.packageName + "/" + serviceInfo.name);
+            return false;
+        }
+        // Looks good.
+        return true;
+    }
+
+    private boolean hasCaptureVideoPermission(String packageName) {
+        if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT,
+                packageName) == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        if (mPackageManager.checkPermission(Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT,
+                packageName) == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        return false;
+    }
+
+    private int findProvider(String packageName, String className) {
+        int count = mProviders.size();
+        for (int i = 0; i < count; i++) {
+            RemoteDisplayProviderProxy provider = mProviders.get(i);
+            if (provider.hasComponentName(packageName, className)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Slog.d(TAG, "Received package manager broadcast: " + intent);
+            }
+            scanPackages();
+        }
+    };
+
+    private final Runnable mScanPackagesRunnable = new Runnable() {
+        @Override
+        public void run() {
+            scanPackages();
+        }
+    };
+
+    public interface Callback {
+        void addProvider(RemoteDisplayProviderProxy provider);
+        void removeProvider(RemoteDisplayProviderProxy provider);
+    }
+}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7291dd4..5450fd0 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1278,7 +1278,8 @@
                 frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
             mFrameworkInstallObserver.startWatching();
             scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
-                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    | PackageParser.PARSE_IS_SYSTEM_DIR
+                    | PackageParser.PARSE_IS_PRIVILEGED,
                     scanMode | SCAN_NO_DEX, 0);
 
             // Collected privileged system packages.
@@ -1771,6 +1772,24 @@
                 state, userId);
     }
 
+    public boolean isPackageAvailable(String packageName, int userId) {
+        if (!sUserManager.exists(userId)) return false;
+        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
+        synchronized (mPackages) {
+            PackageParser.Package p = mPackages.get(packageName);
+            if (p != null) {
+                final PackageSetting ps = (PackageSetting) p.mExtras;
+                if (ps != null) {
+                    final PackageUserState state = ps.readUserState(userId);
+                    if (state != null) {
+                        return PackageParser.isAvailable(state);
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
@@ -10011,11 +10030,11 @@
         }
         if (filter.countDataAuthorities() != 0
                 || filter.countDataPaths() != 0
-                || filter.countDataSchemes() != 0
+                || filter.countDataSchemes() > 1
                 || filter.countDataTypes() != 0) {
             throw new IllegalArgumentException(
                     "replacePreferredActivity expects filter to have no data authorities, " +
-                    "paths, schemes or types.");
+                    "paths, or types; and at most one scheme.");
         }
         synchronized (mPackages) {
             if (mContext.checkCallingOrSelfPermission(
@@ -10032,33 +10051,27 @@
             }
 
             final int callingUserId = UserHandle.getCallingUserId();
-            ArrayList<PreferredActivity> removed = null;
             PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
             if (pir != null) {
-                Iterator<PreferredActivity> it = pir.filterIterator();
-                String action = filter.getAction(0);
-                String category = filter.getCategory(0);
-                while (it.hasNext()) {
-                    PreferredActivity pa = it.next();
-                    if ((pa.countActions() == 0) || (pa.countCategories() == 0)
-                            || (pa.getAction(0).equals(action)
-                                    && pa.getCategory(0).equals(category))) {
-                        if (removed == null) {
-                            removed = new ArrayList<PreferredActivity>();
-                        }
-                        removed.add(pa);
-                        if (DEBUG_PREFERRED) {
-                            Slog.i(TAG, "Removing preferred activity "
-                                    + pa.mPref.mComponent + ":");
-                            filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
-                        }
-                    }
+                Intent intent = new Intent(filter.getAction(0)).addCategory(filter.getCategory(0));
+                if (filter.countDataSchemes() == 1) {
+                    Uri.Builder builder = new Uri.Builder();
+                    builder.scheme(filter.getDataScheme(0));
+                    intent.setData(builder.build());
                 }
-                if (removed != null) {
-                    for (int i=0; i<removed.size(); i++) {
-                        PreferredActivity pa = removed.get(i);
-                        pir.removeFilter(pa);
+                List<PreferredActivity> matches = pir.queryIntent(
+                        intent, null, true, callingUserId);
+                if (DEBUG_PREFERRED) {
+                    Slog.i(TAG, matches.size() + " preferred matches for " + intent);
+                }
+                for (int i = 0; i < matches.size(); i++) {
+                    PreferredActivity pa = matches.get(i);
+                    if (DEBUG_PREFERRED) {
+                        Slog.i(TAG, "Removing preferred activity "
+                                + pa.mPref.mComponent + ":");
+                        filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                     }
+                    pir.removeFilter(pa);
                 }
             }
             addPreferredActivityInternal(filter, match, set, activity, true, callingUserId);
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index d471b57..f2efde1 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -369,15 +369,17 @@
     }
 
     private class BatchedScanRequest extends DeathRecipient {
-        BatchedScanSettings settings;
-        int uid;
-        int pid;
+        final BatchedScanSettings settings;
+        final int uid;
+        final int pid;
+        final WorkSource workSource;
 
-        BatchedScanRequest(BatchedScanSettings settings, IBinder binder) {
+        BatchedScanRequest(BatchedScanSettings settings, IBinder binder, WorkSource ws) {
             super(0, null, binder, null);
             this.settings = settings;
             this.uid = getCallingUid();
             this.pid = getCallingPid();
+            workSource = ws;
         }
         public void binderDied() {
             stopBatchedScan(settings, uid, pid);
@@ -406,12 +408,19 @@
     /**
      * see {@link android.net.wifi.WifiManager#requestBatchedScan()}
      */
-    public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder) {
+    public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder,
+            WorkSource workSource) {
         enforceChangePermission();
+        if (workSource != null) {
+            enforceWorkSourcePermission();
+            // WifiManager currently doesn't use names, so need to clear names out of the
+            // supplied WorkSource to allow future WorkSource combining.
+            workSource.clearNames();
+        }
         if (mBatchedScanSupported == false) return false;
         requested = new BatchedScanSettings(requested);
         if (requested.isInvalid()) return false;
-        BatchedScanRequest r = new BatchedScanRequest(requested, binder);
+        BatchedScanRequest r = new BatchedScanRequest(requested, binder, workSource);
         synchronized(mBatchedScanners) {
             mBatchedScanners.add(r);
             resolveBatchedScannersLocked();
@@ -468,18 +477,48 @@
 
     private void resolveBatchedScannersLocked() {
         BatchedScanSettings setting = new BatchedScanSettings();
+        WorkSource responsibleWorkSource = null;
         int responsibleUid = 0;
+        double responsibleCsph = 0; // Channel Scans Per Hour
 
         if (mBatchedScanners.size() == 0) {
-            mWifiStateMachine.setBatchedScanSettings(null, 0);
+            mWifiStateMachine.setBatchedScanSettings(null, 0, 0, null);
             return;
         }
         for (BatchedScanRequest r : mBatchedScanners) {
             BatchedScanSettings s = r.settings;
+
+            // evaluate responsibility
+            int currentChannelCount;
+            int currentScanInterval;
+            double currentCsph;
+
+            if (s.channelSet == null || s.channelSet.isEmpty()) {
+                // all channels - 11 B and 9 A channels roughly.
+                currentChannelCount = 9 + 11;
+            } else {
+                currentChannelCount = s.channelSet.size();
+                // these are rough est - no real need to correct for reg-domain;
+                if (s.channelSet.contains("A")) currentChannelCount += (9 - 1);
+                if (s.channelSet.contains("B")) currentChannelCount += (11 - 1);
+
+            }
+            if (s.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) {
+                currentScanInterval = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
+            } else {
+                currentScanInterval = s.scanIntervalSec;
+            }
+            currentCsph = 60 * 60 * currentChannelCount / currentScanInterval;
+
+            if (currentCsph > responsibleCsph) {
+                responsibleUid = r.uid;
+                responsibleWorkSource = r.workSource;
+                responsibleCsph = currentCsph;
+            }
+
             if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
                     s.maxScansPerBatch < setting.maxScansPerBatch) {
                 setting.maxScansPerBatch = s.maxScansPerBatch;
-                responsibleUid = r.uid;
             }
             if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
                     (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED ||
@@ -489,7 +528,6 @@
             if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
                     s.scanIntervalSec < setting.scanIntervalSec) {
                 setting.scanIntervalSec = s.scanIntervalSec;
-                responsibleUid = r.uid;
             }
             if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
                     (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED ||
@@ -511,7 +549,8 @@
         }
 
         setting.constrain();
-        mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid);
+        mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid, (int)responsibleCsph,
+                responsibleWorkSource);
     }
 
     private void enforceAccessPermission() {
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 8cc1d02..e98014b 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -53,6 +53,7 @@
     int groupId = -1;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+    boolean layoutConfigChanges;
     boolean showWhenLocked;
 
     // The input dispatching timeout for this application token in nanoseconds.
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 52f2325..d358b4c 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -25,9 +25,11 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Debug;
+import android.util.EventLog;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
+import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -97,9 +99,6 @@
     /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
     private TaskStack mHomeStack = null;
 
-    /** Sorted most recent at top, oldest at [0]. */
-    ArrayList<TaskStack> mStackHistory = new ArrayList<TaskStack>();
-
     /** Detect user tapping outside of current focused stack bounds .*/
     StackTapPointerEventListener mTapDetector;
 
@@ -107,7 +106,7 @@
     Region mTouchExcludeRegion = new Region();
 
     /** Save allocating when retrieving tasks */
-    ArrayList<Task> mTaskHistory = new ArrayList<Task>();
+    private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
 
     /** Save allocating when calculating rects */
     Rect mTmpRect = new Rect();
@@ -160,12 +159,6 @@
         return mStackBoxes.get(0).mStack != mHomeStack;
     }
 
-    void moveStack(TaskStack stack, boolean toTop) {
-        mStackHistory.remove(stack);
-        mStackHistory.add(toTop ? mStackHistory.size() : 0, stack);
-        mService.moveStackWindowsLocked(this);
-    }
-
     public boolean isPrivate() {
         return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
     }
@@ -200,6 +193,7 @@
         }
 
         mTaskHistory.add(taskNdx, task);
+        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
     }
 
     void removeTask(Task task) {
@@ -277,6 +271,8 @@
         if (newStack != null) {
             layoutNeeded = true;
         }
+        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,
+                (int)(weight * 100 + 0.5));
         return newStack;
     }
 
@@ -345,6 +341,7 @@
     boolean moveHomeStackBox(boolean toTop) {
         if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +
                 Debug.getCallers(4));
+        EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);
         switch (mStackBoxes.size()) {
             case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
             case 1: return false; // Only the home StackBox exists.
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
index d054e9a..d351925 100644
--- a/services/java/com/android/server/wm/StackBox.java
+++ b/services/java/com/android/server/wm/StackBox.java
@@ -243,10 +243,6 @@
     /** Remove this box and propagate its sibling's content up to their parent.
      * @return The first stackId of the resulting StackBox. */
     int remove() {
-        if (mStack != null) {
-            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing stackId=" + mStack.mStackId);
-            mDisplayContent.mStackHistory.remove(mStack);
-        }
         mDisplayContent.layoutNeeded = true;
 
         if (mParent == null) {
diff --git a/services/java/com/android/server/wm/Task.java b/services/java/com/android/server/wm/Task.java
index d9acbb9..13fdbc8 100644
--- a/services/java/com/android/server/wm/Task.java
+++ b/services/java/com/android/server/wm/Task.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wm;
 
+import android.util.EventLog;
+import com.android.server.EventLogTags;
+
 class Task {
 //    private final String TAG = "TaskGroup";
     TaskStack mStack;
@@ -41,6 +44,8 @@
     boolean removeAppToken(AppWindowToken wtoken) {
         mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
+            EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
+                    "removeAppToken: last token");
             mStack.removeTask(this);
             return true;
         }
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index 34bef68..cb29df4 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -21,8 +21,10 @@
 
 import android.graphics.Rect;
 import android.os.Debug;
+import android.util.EventLog;
 import android.util.Slog;
 import android.util.TypedValue;
+import com.android.server.EventLogTags;
 
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
@@ -45,7 +47,7 @@
 
     /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
      * mTaskHistory in the ActivityStack with the same mStackId */
-    private ArrayList<Task> mTasks = new ArrayList<Task>();
+    private final ArrayList<Task> mTasks = new ArrayList<Task>();
 
     /** The StackBox this sits in. */
     StackBox mStackBox;
@@ -70,7 +72,6 @@
         mService = service;
         mStackId = stackId;
         mDisplayContent = displayContent;
-        final int displayId = displayContent.getDisplayId();
         mDimLayer = new DimLayer(service, this);
         mAnimationBackgroundSurface = new DimLayer(service, this);
     }
@@ -152,6 +153,7 @@
     int remove() {
         mAnimationBackgroundSurface.destroySurface();
         mDimLayer.destroySurface();
+        EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
         return mStackBox.remove();
     }
 
@@ -269,6 +271,8 @@
                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                     final WindowState win = windows.get(winNdx);
                     if (!resizingWindows.contains(win)) {
+                        if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
+                                "setBounds: Resizing " + win);
                         resizingWindows.add(win);
                     }
                     win.mUnderStatusBar = underStatusBar;
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index cd46bb8..91f15f3 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -245,7 +245,7 @@
                                 mForceHiding = KEYGUARD_ANIMATING_OUT;
                             }
                         } else {
-                            mForceHiding = KEYGUARD_SHOWN;
+                            mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
                         }
                     }
                     if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index e1e9f5c..3ed5076 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -578,10 +578,13 @@
         private boolean mUpdateRotation = false;
         boolean mWallpaperActionPending = false;
 
-        private static final int DISPLAY_CONTENT_UNKNOWN = 0;
-        private static final int DISPLAY_CONTENT_MIRROR = 1;
-        private static final int DISPLAY_CONTENT_UNIQUE = 2;
-        private int mDisplayHasContent = DISPLAY_CONTENT_UNKNOWN;
+        // Set to true when the display contains content to show the user.
+        // When false, the display manager may choose to mirror or blank the display.
+        boolean mDisplayHasContent = false;
+
+        // Only set while traversing the default display based on its content.
+        // Affects the behavior of mirroring on secondary displays.
+        boolean mObscureApplicationContentOnSecondaryDisplays = false;
     }
     final LayoutFields mInnerFields = new LayoutFields();
 
@@ -3394,16 +3397,17 @@
         if (stack == null) {
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
+        EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
         Task task = new Task(atoken, stack, userId);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, true);
-        stack.getDisplayContent().moveStack(stack, true);
         return task;
     }
 
     @Override
     public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
-            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId) {
+            int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
+            int configChanges) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3435,6 +3439,8 @@
             atoken.appFullscreen = fullscreen;
             atoken.showWhenLocked = showWhenLocked;
             atoken.requestedOrientation = requestedOrientation;
+            atoken.layoutConfigChanges = (configChanges &
+                    (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
@@ -4303,10 +4309,6 @@
             // If we are preparing an app transition, then delay changing
             // the visibility of this token until we execute that transition.
             if (okToDisplay() && mAppTransition.isTransitionSet()) {
-                // Already in requested state, don't do anything more.
-                if (wtoken.hiddenRequested != visible) {
-                    return;
-                }
                 wtoken.hiddenRequested = !visible;
 
                 if (!wtoken.startingDisplayed) {
@@ -4792,7 +4794,6 @@
                     displayContent.moveHomeStackBox(isHomeStackTask);
                 }
                 stack.moveTaskToTop(task);
-                displayContent.moveStack(stack, true);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -4846,7 +4847,6 @@
                         weight);
                 if (stack != null) {
                     mStackIdToStack.put(stackId, stack);
-                    displayContent.moveStack(stack, true);
                     performLayoutAndPlaceSurfacesLocked();
                     return;
                 }
@@ -4878,6 +4878,7 @@
                 return;
             }
             final TaskStack stack = task.mStack;
+            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
             stack.removeTask(task);
             stack.getDisplayContent().layoutNeeded = true;
         }
@@ -8269,8 +8270,9 @@
             // windows, since that means "perform layout as normal,
             // just don't display").
             if (!gone || !win.mHaveFrame || win.mLayoutNeeded
-                    || win.mAttrs.type == TYPE_KEYGUARD && win.isConfigChanged()
-                    || mOpeningApps.contains(win.mAppToken)
+                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
+                            (win.mAttrs.type == TYPE_KEYGUARD ||
+                            win.mAppToken != null && win.mAppToken.layoutConfigChanges))
                     || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
                 if (!win.mLayoutAttached) {
                     if (initial) {
@@ -8704,12 +8706,7 @@
     private void updateResizingWindows(final WindowState w) {
         final WindowStateAnimator winAnimator = w.mWinAnimator;
         if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
-            w.mOverscanInsetsChanged |=
-                    !w.mLastOverscanInsets.equals(w.mOverscanInsets);
-            w.mContentInsetsChanged |=
-                    !w.mLastContentInsets.equals(w.mContentInsets);
-            w.mVisibleInsetsChanged |=
-                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
+            w.setInsetsChanged();
             boolean configChanged = w.isConfigChanged();
             if (DEBUG_CONFIGURATION && configChanged) {
                 Slog.v(TAG, "Win " + w + " config changed: "
@@ -8784,6 +8781,14 @@
         final WindowManager.LayoutParams attrs = w.mAttrs;
         final int attrFlags = attrs.flags;
         final boolean canBeSeen = w.isDisplayedLw();
+        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
+
+        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
+            // This window completely covers everything behind it,
+            // so we want to leave all of them as undimmed (for
+            // performance reasons).
+            mInnerFields.mObscured = true;
+        }
 
         if (w.mHasSurface) {
             if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
@@ -8812,22 +8817,24 @@
             }
 
             if (canBeSeen) {
-                if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
-                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR;
-                } else if (mInnerFields.mDisplayHasContent
-                        == LayoutFields.DISPLAY_CONTENT_UNKNOWN) {
-                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE;
+                // This function assumes that the contents of the default display are
+                // processed first before secondary displays.
+                if (w.mDisplayContent.isDefaultDisplay) {
+                    // While a dream or keyguard is showing, obscure ordinary application
+                    // content on secondary displays (by forcibly enabling mirroring unless
+                    // there is other content we want to show) but still allow opaque
+                    // keyguard dialogs to be shown.
+                    if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
+                        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
+                    }
+                    mInnerFields.mDisplayHasContent = true;
+                } else if (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
+                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG)) {
+                    // Allow full screen keyguard presentation dialogs to be seen.
+                    mInnerFields.mDisplayHasContent = true;
                 }
             }
         }
-
-        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
-        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
-            // This window completely covers everything behind it,
-            // so we want to leave all of them as undimmed (for
-            // performance reasons).
-            mInnerFields.mObscured = true;
-        }
     }
 
     private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) {
@@ -8905,7 +8912,7 @@
         mInnerFields.mScreenBrightness = -1;
         mInnerFields.mButtonBrightness = -1;
         mInnerFields.mUserActivityTimeout = -1;
-        mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
+        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
 
         mTransactionSequence++;
 
@@ -8940,10 +8947,8 @@
                 final int innerDh = displayInfo.appHeight;
                 final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
 
-                // Reset for each display unless we are forcing mirroring.
-                if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
-                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
-                }
+                // Reset for each display.
+                mInnerFields.mDisplayHasContent = false;
 
                 int repeats = 0;
                 do {
@@ -9152,20 +9157,8 @@
                     updateResizingWindows(w);
                 }
 
-                final boolean hasUniqueContent;
-                switch (mInnerFields.mDisplayHasContent) {
-                    case LayoutFields.DISPLAY_CONTENT_MIRROR:
-                        hasUniqueContent = isDefaultDisplay;
-                        break;
-                    case LayoutFields.DISPLAY_CONTENT_UNIQUE:
-                        hasUniqueContent = true;
-                        break;
-                    case LayoutFields.DISPLAY_CONTENT_UNKNOWN:
-                    default:
-                        hasUniqueContent = false;
-                        break;
-                }
-                mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
+                mDisplayManagerService.setDisplayHasContent(displayId,
+                        mInnerFields.mDisplayHasContent,
                         true /* inTraversal, must call performTraversalInTrans... below */);
 
                 getDisplayContentLocked(displayId).stopDimmingIfNeeded();
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 2d08792..4d53cea 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -701,6 +701,13 @@
         return mAppToken != null ? mAppToken.appToken : null;
     }
 
+    boolean setInsetsChanged() {
+        mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
+        mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
+        mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
+        return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged;
+    }
+
     public int getDisplayId() {
         return mDisplayContent.getDisplayId();
     }
diff --git a/tests/RemoteDisplayProvider/Android.mk b/tests/RemoteDisplayProvider/Android.mk
new file mode 100644
index 0000000..2f4b343
--- /dev/null
+++ b/tests/RemoteDisplayProvider/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2013 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the application.
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := RemoteDisplayProviderTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
+LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay
+LOCAL_CERTIFICATE := platform
+include $(BUILD_PACKAGE)
diff --git a/tests/RemoteDisplayProvider/AndroidManifest.xml b/tests/RemoteDisplayProvider/AndroidManifest.xml
new file mode 100644
index 0000000..afb7c78
--- /dev/null
+++ b/tests/RemoteDisplayProvider/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.android.media.remotedisplay.test" >
+
+    <uses-sdk android:minSdkVersion="19" />
+    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
+
+    <application android:label="@string/app_name"
+            android:icon="@drawable/ic_app">
+        <uses-library android:name="com.android.media.remotedisplay"
+                android:required="true" />
+
+        <service android:name=".RemoteDisplayProviderService"
+                android:label="@string/app_name"
+                android:exported="true"
+                android:permission="android.permission.BIND_REMOTE_DISPLAY">
+            <intent-filter>
+                <action android:name="com.android.media.remotedisplay.RemoteDisplayProvider"/>
+            </intent-filter>
+        </service>
+
+    </application>
+</manifest>
diff --git a/tests/RemoteDisplayProvider/README b/tests/RemoteDisplayProvider/README
new file mode 100644
index 0000000..8bf0130
--- /dev/null
+++ b/tests/RemoteDisplayProvider/README
@@ -0,0 +1,16 @@
+This directory contains sample code to test system integration with
+remote display providers using the API declared by the
+com.android.media.remotedisplay.jar library.
+
+--- DESCRIPTION ---
+
+The application registers a service that publishes a few different
+remote display routes.  Behavior can be controlled by modifying the
+code.
+
+To exercise the provider, use System UI features for connecting to
+wireless displays or launch an activity that uses the MediaRouter,
+such as the PresentationWithMediaRouterActivity in ApiDemos.
+
+This code is mainly intended for development and not meant to be
+used as an example implementation of a robust remote display provider.
diff --git a/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png b/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png b/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/RemoteDisplayProvider/res/values/strings.xml b/tests/RemoteDisplayProvider/res/values/strings.xml
new file mode 100644
index 0000000..dd82d2c
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">Remote Display Provider Test</string>
+</resources>
diff --git a/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java b/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java
new file mode 100644
index 0000000..611d7e4
--- /dev/null
+++ b/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2013 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.android.media.remotedisplay.test;
+
+import com.android.media.remotedisplay.RemoteDisplay;
+import com.android.media.remotedisplay.RemoteDisplayProvider;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Remote display provider implementation that publishes working routes.
+ */
+public class RemoteDisplayProviderService extends Service {
+    private static final String TAG = "RemoteDisplayProviderTest";
+
+    private Provider mProvider;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
+            if (mProvider == null) {
+                mProvider = new Provider();
+                return mProvider.getBinder();
+            }
+        }
+        return null;
+    }
+
+    final class Provider extends RemoteDisplayProvider {
+        private RemoteDisplay mTestDisplay1; // variable volume
+        private RemoteDisplay mTestDisplay2; // fixed volume
+        private RemoteDisplay mTestDisplay3; // not available
+        private RemoteDisplay mTestDisplay4; // in use
+        private RemoteDisplay mTestDisplay5; // available but ignores request to connect
+        private RemoteDisplay mTestDisplay6; // available but never finishes connecting
+        private RemoteDisplay mTestDisplay7; // blinks in and out of existence
+        private RemoteDisplay mTestDisplay8; // available but connecting attempt flakes out
+        private RemoteDisplay mTestDisplay9; // available but connection flakes out
+        private RemoteDisplay mTestDisplay10; // available and reconnects periodically
+
+        private final Handler mHandler;
+        private boolean mBlinking;
+
+        public Provider() {
+            super(RemoteDisplayProviderService.this);
+            mHandler = new Handler(getMainLooper());
+        }
+
+        @Override
+        public void onDiscoveryModeChanged(int mode) {
+            Log.d(TAG, "onDiscoveryModeChanged: mode=" + mode);
+
+            if (mode != DISCOVERY_MODE_NONE) {
+                // When discovery begins, go find all of the routes.
+                if (mTestDisplay1 == null) {
+                    mTestDisplay1 = new RemoteDisplay("testDisplay1",
+                            "Test Display 1 (variable)");
+                    mTestDisplay1.setDescription("Variable volume");
+                    mTestDisplay1.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    mTestDisplay1.setVolume(10);
+                    mTestDisplay1.setVolumeHandling(RemoteDisplay.PLAYBACK_VOLUME_VARIABLE);
+                    mTestDisplay1.setVolumeMax(15);
+                    addDisplay(mTestDisplay1);
+                }
+                if (mTestDisplay2 == null) {
+                    mTestDisplay2 = new RemoteDisplay("testDisplay2",
+                            "Test Display 2 (fixed)");
+                    mTestDisplay2.setDescription("Fixed volume");
+                    mTestDisplay2.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay2);
+                }
+                if (mTestDisplay3 == null) {
+                    mTestDisplay3 = new RemoteDisplay("testDisplay3",
+                            "Test Display 3 (unavailable)");
+                    mTestDisplay3.setDescription("Always unavailable");
+                    mTestDisplay3.setStatus(RemoteDisplay.STATUS_NOT_AVAILABLE);
+                    addDisplay(mTestDisplay3);
+                }
+                if (mTestDisplay4 == null) {
+                    mTestDisplay4 = new RemoteDisplay("testDisplay4",
+                            "Test Display 4 (in-use)");
+                    mTestDisplay4.setDescription("Always in-use");
+                    mTestDisplay4.setStatus(RemoteDisplay.STATUS_IN_USE);
+                    addDisplay(mTestDisplay4);
+                }
+                if (mTestDisplay5 == null) {
+                    mTestDisplay5 = new RemoteDisplay("testDisplay5",
+                            "Test Display 5 (connect ignored)");
+                    mTestDisplay5.setDescription("Ignores connect");
+                    mTestDisplay5.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay5);
+                }
+                if (mTestDisplay6 == null) {
+                    mTestDisplay6 = new RemoteDisplay("testDisplay6",
+                            "Test Display 6 (connect hangs)");
+                    mTestDisplay6.setDescription("Never finishes connecting");
+                    mTestDisplay6.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay6);
+                }
+                if (mTestDisplay8 == null) {
+                    mTestDisplay8 = new RemoteDisplay("testDisplay8",
+                            "Test Display 8 (flaky when connecting)");
+                    mTestDisplay8.setDescription("Aborts spontaneously while connecting");
+                    mTestDisplay8.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay8);
+                }
+                if (mTestDisplay9 == null) {
+                    mTestDisplay9 = new RemoteDisplay("testDisplay9",
+                            "Test Display 9 (flaky when connected)");
+                    mTestDisplay9.setDescription("Aborts spontaneously while connected");
+                    mTestDisplay9.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay9);
+                }
+                if (mTestDisplay10 == null) {
+                    mTestDisplay10 = new RemoteDisplay("testDisplay10",
+                            "Test Display 10 (reconnects periodically)");
+                    mTestDisplay10.setDescription("Reconnects spontaneously");
+                    mTestDisplay10.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay10);
+                }
+            } else {
+                // When discovery ends, go hide some of the routes we can't actually use.
+                // This isn't something a normal route provider would do though.
+                // The routes will usually stay published.
+                if (mTestDisplay3 != null) {
+                    removeDisplay(mTestDisplay3);
+                    mTestDisplay3 = null;
+                }
+                if (mTestDisplay4 != null) {
+                    removeDisplay(mTestDisplay4);
+                    mTestDisplay4 = null;
+                }
+            }
+
+            // When active discovery is on, pretend there's a route that we can't quite
+            // reach that blinks in and out of existence.
+            if (mode == DISCOVERY_MODE_ACTIVE) {
+                if (!mBlinking) {
+                    mBlinking = true;
+                    mHandler.post(mBlink);
+                }
+            } else {
+                mBlinking = false;
+            }
+        }
+
+        @Override
+        public void onConnect(final RemoteDisplay display) {
+            Log.d(TAG, "onConnect: display.getId()=" + display.getId());
+
+            if (display == mTestDisplay1 || display == mTestDisplay2) {
+                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                updateDisplay(display);
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        if ((display == mTestDisplay1 || display == mTestDisplay2)
+                                && display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+                            display.setStatus(RemoteDisplay.STATUS_CONNECTED);
+                            updateDisplay(display);
+                        }
+                    }
+                }, 2000);
+            } else if (display == mTestDisplay6 || display == mTestDisplay7) {
+                // never finishes connecting
+                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                updateDisplay(display);
+            } else if (display == mTestDisplay8) {
+                // flakes out while connecting
+                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                updateDisplay(display);
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        if ((display == mTestDisplay8)
+                                && display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+                            display.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                            updateDisplay(display);
+                        }
+                    }
+                }, 2000);
+            } else if (display == mTestDisplay9) {
+                // flakes out when connected
+                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                updateDisplay(display);
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        if ((display == mTestDisplay9)
+                                && display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+                            display.setStatus(RemoteDisplay.STATUS_CONNECTED);
+                            updateDisplay(display);
+                        }
+                    }
+                }, 2000);
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        if ((display == mTestDisplay9)
+                                && display.getStatus() == RemoteDisplay.STATUS_CONNECTED) {
+                            display.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                            updateDisplay(display);
+                        }
+                    }
+                }, 5000);
+            } else if (display == mTestDisplay10) {
+                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                updateDisplay(display);
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (display == mTestDisplay10) {
+                            if (display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+                                display.setStatus(RemoteDisplay.STATUS_CONNECTED);
+                                updateDisplay(display);
+                                mHandler.postDelayed(this, 7000);
+                            } else if (display.getStatus() == RemoteDisplay.STATUS_CONNECTED) {
+                                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                                updateDisplay(display);
+                                mHandler.postDelayed(this, 2000);
+                            }
+                        }
+                    }
+                }, 2000);
+            }
+        }
+
+        @Override
+        public void onDisconnect(RemoteDisplay display) {
+            Log.d(TAG, "onDisconnect: display.getId()=" + display.getId());
+
+            if (display == mTestDisplay1 || display == mTestDisplay2
+                    || display == mTestDisplay6 || display == mTestDisplay8
+                    || display == mTestDisplay9 || display == mTestDisplay10) {
+                display.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                updateDisplay(display);
+            }
+        }
+
+        @Override
+        public void onSetVolume(RemoteDisplay display, int volume) {
+            Log.d(TAG, "onSetVolume: display.getId()=" + display.getId()
+                    + ", volume=" + volume);
+
+            if (display == mTestDisplay1) {
+                display.setVolume(Math.max(0, Math.min(display.getVolumeMax(), volume)));
+                updateDisplay(display);
+            }
+        }
+
+        @Override
+        public void onAdjustVolume(RemoteDisplay display, int delta) {
+            Log.d(TAG, "onAdjustVolume: display.getId()=" + display.getId()
+                    + ", delta=" + delta);
+
+            if (display == mTestDisplay1) {
+                display.setVolume(Math.max(0, Math.min(display.getVolumeMax(),
+                        display .getVolume() + delta)));
+                updateDisplay(display);
+            }
+        }
+
+        @Override
+        public void addDisplay(RemoteDisplay display) {
+            Log.d(TAG, "addDisplay: display=" + display);
+            super.addDisplay(display);
+        }
+
+        @Override
+        public void removeDisplay(RemoteDisplay display) {
+            Log.d(TAG, "removeDisplay: display=" + display);
+            super.removeDisplay(display);
+        }
+
+        @Override
+        public void updateDisplay(RemoteDisplay display) {
+            Log.d(TAG, "updateDisplay: display=" + display);
+            super.updateDisplay(display);
+        }
+
+        private final Runnable mBlink = new Runnable() {
+            @Override
+            public void run() {
+                if (mTestDisplay7 == null) {
+                    if (mBlinking) {
+                        mTestDisplay7 = new RemoteDisplay("testDisplay7",
+                                "Test Display 7 (blinky)");
+                        mTestDisplay7.setDescription("Comes and goes but can't connect");
+                        mTestDisplay7.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                        addDisplay(mTestDisplay7);
+                        mHandler.postDelayed(this, 7000);
+                    }
+                } else {
+                    removeDisplay(mTestDisplay7);
+                    mTestDisplay7 = null;
+                    if (mBlinking) {
+                        mHandler.postDelayed(this, 4000);
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index e4c4214..df32ee1 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
         }
         
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 4e73568..ed497a5 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -31,6 +31,9 @@
 built_core_dep := $(call java-lib-deps,core)
 built_core_classes := $(call java-lib-files,core)
 
+built_ext_dep := $(call java-lib-deps,ext)
+built_ext_classes := $(call java-lib-files,ext)
+
 built_layoutlib_create_jar := $(call intermediates-dir-for, \
 			JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
 
@@ -47,6 +50,7 @@
 
 $(LOCAL_BUILT_MODULE): $(built_core_dep) \
                        $(built_framework_dep) \
+                       $(built_ext_dep) \
                        $(built_layoutlib_create_jar)
 	$(hide) echo "host layoutlib_create: $@"
 	$(hide) mkdir -p $(dir $@)
@@ -55,7 +59,8 @@
 	$(hide) java -jar $(built_layoutlib_create_jar) \
 	             $@ \
 	             $(built_core_classes) \
-	             $(built_framework_classes)
+	             $(built_framework_classes) \
+	             $(built_ext_classes)
 	$(hide) ls -l $(built_framework_classes)
 
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index ec284ac..93284db 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -308,8 +308,9 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeRecycle(int nativeBitmap) {
+    /*package*/ static boolean nativeRecycle(int nativeBitmap) {
         sManager.removeJavaReferenceFor(nativeBitmap);
+        return true;
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index fd153af..dd2cbc1 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -81,7 +81,7 @@
 
     @Override
     public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
-            boolean arg5, boolean arg6, int arg7)
+            boolean arg5, boolean arg6, int arg7, int arg8)
             throws RemoteException {
         // TODO Auto-generated method stub
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 17b0eb6..bcd08eb4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -290,7 +290,7 @@
                     TypedValue out = new TypedValue();
                     if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out,
                             true /*requireUnit*/)) {
-                        textView.setTextSize(
+                        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                                 out.getDimension(bridgeContext.getResources().getDisplayMetrics()));
                     }
                 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 23d08e3..60f5331 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -273,7 +273,6 @@
             mContext.getRenderResources().setLogger(null);
         }
 
-        mContext = null;
     }
 
     public static BridgeContext getCurrentContext() {
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 06ae804..ad4103b 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -46,7 +46,7 @@
     // --- Native methods accessing ICU's database.
 
     @LayoutlibDelegate
-    /*package*/ static String getBestDateTimePattern(String skeleton, String localeName) {
+    /*package*/ static String getBestDateTimePatternNative(String skeleton, String localeName) {
         return DateTimePatternGenerator.getInstance(new ULocale(localeName))
                 .getBestPattern(skeleton);
     }
@@ -167,7 +167,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean initLocaleDataImpl(String locale, LocaleData result) {
+    /*package*/ static boolean initLocaleDataNative(String locale, LocaleData result) {
 
         // Used by Calendar.
         result.firstDayOfWeek = Integer.valueOf(1);
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index ba23048..ee501d2 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -113,6 +113,7 @@
                         "android.pim.*", // for datepicker
                         "android.os.*",  // for android.os.Handler
                         "android.database.ContentObserver", // for Digital clock
+                        "com.android.i18n.phonenumbers.*",  // for TextView with autolink attribute
                     },
                     excludeClasses);
             aa.analyze();
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 5a1928c..149bda6 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -117,7 +117,7 @@
 
     void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
 
-    boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder);
+    boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder, in WorkSource ws);
 
     void stopBatchedScan(in BatchedScanSettings requested);
 
diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/wifi/java/android/net/wifi/SupplicantStateTracker.java
index f6a621f..e76eb17 100644
--- a/wifi/java/android/net/wifi/SupplicantStateTracker.java
+++ b/wifi/java/android/net/wifi/SupplicantStateTracker.java
@@ -55,7 +55,7 @@
     private static final int MAX_RETRIES_ON_AUTHENTICATION_FAILURE = 2;
 
     /* Maximum retries on assoc rejection events */
-    private static final int MAX_RETRIES_ON_ASSOCIATION_REJECT = 4;
+    private static final int MAX_RETRIES_ON_ASSOCIATION_REJECT = 16;
 
     /* Tracks if networks have been disabled during a connection */
     private boolean mNetworksDisabledDuringConnect = false;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7fc8bef..3b47e63 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -799,7 +799,13 @@
      */
     public boolean requestBatchedScan(BatchedScanSettings requested) {
         try {
-            return mService.requestBatchedScan(requested, new Binder());
+            return mService.requestBatchedScan(requested, new Binder(), null);
+        } catch (RemoteException e) { return false; }
+    }
+    /** @hide */
+    public boolean requestBatchedScan(BatchedScanSettings requested, WorkSource workSource) {
+        try {
+            return mService.requestBatchedScan(requested, new Binder(), workSource);
         } catch (RemoteException e) { return false; }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 520668e..c2f278a 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -39,7 +39,6 @@
 public class WifiNative {
 
     private static final boolean DBG = false;
-    private static final boolean VDBG = false;
     private final String mTAG;
     private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
 
@@ -118,12 +117,12 @@
 
     public boolean connectToSupplicant() {
         // No synchronization necessary .. it is implemented in WifiMonitor
-        if (VDBG) localLog(mInterfacePrefix + "connectToSupplicant");
+        localLog(mInterfacePrefix + "connectToSupplicant");
         return connectToSupplicantNative();
     }
 
     public void closeSupplicantConnection() {
-        if (VDBG) localLog(mInterfacePrefix + "closeSupplicantConnection");
+        localLog(mInterfacePrefix + "closeSupplicantConnection");
         closeSupplicantConnectionNative();
     }
 
@@ -136,9 +135,9 @@
         if (DBG) Log.d(mTAG, "doBoolean: " + command);
         synchronized (mLock) {
             int cmdId = getNewCmdIdLocked();
-            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            localLog(cmdId + "->" + mInterfacePrefix + command);
             boolean result = doBooleanCommandNative(mInterfacePrefix + command);
-            if (VDBG) localLog(cmdId + "<-" + result);
+            localLog(cmdId + "<-" + result);
             if (DBG) Log.d(mTAG, "   returned " + result);
             return result;
         }
@@ -148,9 +147,9 @@
         if (DBG) Log.d(mTAG, "doInt: " + command);
         synchronized (mLock) {
             int cmdId = getNewCmdIdLocked();
-            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            localLog(cmdId + "->" + mInterfacePrefix + command);
             int result = doIntCommandNative(mInterfacePrefix + command);
-            if (VDBG) localLog(cmdId + "<-" + result);
+            localLog(cmdId + "<-" + result);
             if (DBG) Log.d(mTAG, "   returned " + result);
             return result;
         }
@@ -160,9 +159,9 @@
         if (DBG) Log.d(mTAG, "doString: " + command);
         synchronized (mLock) {
             int cmdId = getNewCmdIdLocked();
-            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            localLog(cmdId + "->" + mInterfacePrefix + command);
             String result = doStringCommandNative(mInterfacePrefix + command);
-            if (VDBG) localLog(cmdId + "<-" + result);
+            localLog(cmdId + "<-" + result);
             if (DBG) Log.d(mTAG, "   returned " + result);
             return result;
         }
@@ -298,7 +297,9 @@
      * the firmware can remember before it runs out of buffer space or -1 on error
      */
     public String setBatchedScanSettings(BatchedScanSettings settings) {
-        if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP");
+        if (settings == null) {
+            return doStringCommand("DRIVER WLS_BATCHING STOP");
+        }
         String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec;
         cmd += " MSCAN=" + settings.maxScansPerBatch;
         if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 78da7e7..eedd66f 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -57,6 +57,7 @@
 import android.net.wifi.p2p.WifiP2pService;
 import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Message;
@@ -416,7 +417,8 @@
 
     /* change the batch scan settings.
      * arg1 = responsible UID
-     * obj = the new settings
+     * arg2 = csph (channel scans per hour)
+     * obj = bundle with the new settings and the optional worksource
      */
     public static final int CMD_SET_BATCHED_SCAN          = BASE + 135;
     public static final int CMD_START_NEXT_BATCHED_SCAN   = BASE + 136;
@@ -628,6 +630,15 @@
 
     private BatchedScanSettings mBatchedScanSettings = null;
 
+    /**
+     * Track the worksource/cost of the current settings and track what's been noted
+     * to the battery stats, so we can mark the end of the previous when changing.
+     */
+    private WorkSource mBatchedScanWorkSource = null;
+    private int mBatchedScanCsph = 0;
+    private WorkSource mNotedBatchedScanWorkSource = null;
+    private int mNotedBatchedScanCsph = 0;
+
 
     public WifiStateMachine(Context context, String wlanInterface) {
         super("WifiStateMachine");
@@ -841,8 +852,14 @@
     /**
      * start or stop batched scanning using the given settings
      */
-    public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid) {
-        sendMessage(CMD_SET_BATCHED_SCAN, callingUid, 0, settings);
+    private static final String BATCHED_SETTING = "batched_settings";
+    private static final String BATCHED_WORKSOURCE = "batched_worksource";
+    public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph,
+            WorkSource workSource) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(BATCHED_SETTING, settings);
+        bundle.putParcelable(BATCHED_WORKSOURCE, workSource);
+        sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle);
     }
 
     public List<BatchedScanResult> syncGetBatchedScanResultsList() {
@@ -861,6 +878,8 @@
     }
 
     private void startBatchedScan() {
+        if (mBatchedScanSettings == null) return;
+
         if (mDhcpActive) {
             if (DBG) log("not starting Batched Scans due to DHCP");
             return;
@@ -872,10 +891,10 @@
         mAlarmManager.cancel(mBatchedScanIntervalIntent);
 
         String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
-
         try {
             mExpectedBatchedScans = Integer.parseInt(scansExpected);
             setNextBatchedAlarm(mExpectedBatchedScans);
+            if (mExpectedBatchedScans > 0) noteBatchedScanStart();
         } catch (NumberFormatException e) {
             stopBatchedScan();
             loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
@@ -918,25 +937,31 @@
     }
 
     // return true if new/different
-    private boolean recordBatchedScanSettings(BatchedScanSettings settings) {
-        if (DBG) log("set batched scan to " + settings);
+    private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) {
+        BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING);
+        WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE);
+
+        if (DBG) {
+            log("set batched scan to " + settings + " for uid=" + responsibleUid +
+                    ", worksource=" + responsibleWorkSource);
+        }
         if (settings != null) {
-            // TODO - noteBatchedScanStart(message.arg1);
             if (settings.equals(mBatchedScanSettings)) return false;
         } else {
             if (mBatchedScanSettings == null) return false;
-            // TODO - noteBatchedScanStop(message.arg1);
         }
         mBatchedScanSettings = settings;
+        if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid);
+        mBatchedScanWorkSource = responsibleWorkSource;
+        mBatchedScanCsph = csph;
         return true;
     }
 
     private void stopBatchedScan() {
         mAlarmManager.cancel(mBatchedScanIntervalIntent);
-        if (mBatchedScanSettings != null) {
-            retrieveBatchedScanData();
-            mWifiNative.setBatchedScanSettings(null);
-        }
+        retrieveBatchedScanData();
+        mWifiNative.setBatchedScanSettings(null);
+        noteBatchedScanStop();
     }
 
     private void setNextBatchedAlarm(int scansExpected) {
@@ -1164,6 +1189,44 @@
         }
     }
 
+    private void noteBatchedScanStart() {
+        // note the end of a previous scan set
+        if (mNotedBatchedScanWorkSource != null &&
+                (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false ||
+                 mNotedBatchedScanCsph != mBatchedScanCsph)) {
+            try {
+                mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
+            } catch (RemoteException e) {
+                log(e.toString());
+            } finally {
+                mNotedBatchedScanWorkSource = null;
+                mNotedBatchedScanCsph = 0;
+            }
+        }
+        // note the start of the new
+        try {
+            mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource,
+                    mBatchedScanCsph);
+            mNotedBatchedScanWorkSource = mBatchedScanWorkSource;
+            mNotedBatchedScanCsph = mBatchedScanCsph;
+        } catch (RemoteException e) {
+            log(e.toString());
+        }
+    }
+
+    private void noteBatchedScanStop() {
+        if (mNotedBatchedScanWorkSource != null) {
+            try {
+                mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
+            } catch (RemoteException e) {
+                log(e.toString());
+            } finally {
+                mNotedBatchedScanWorkSource = null;
+                mNotedBatchedScanCsph = 0;
+            }
+        }
+    }
+
     private void startScanNative(int type) {
         mWifiNative.scan(type);
         mScanResultIsPending = true;
@@ -1868,6 +1931,9 @@
            return;
         }
 
+        // note that all these splits and substrings keep references to the original
+        // huge string buffer while the amount we really want is generally pretty small
+        // so make copies instead (one example b/11087956 wasted 400k of heap here).
         synchronized(mScanResultCache) {
             mScanResults = new ArrayList<ScanResult>();
             String[] lines = scanResults.split("\n");
@@ -2307,9 +2373,7 @@
 
         mDhcpActive = false;
 
-        if (mBatchedScanSettings != null) {
-            startBatchedScan();
-        }
+        startBatchedScan();
     }
 
     private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) {
@@ -2447,7 +2511,7 @@
                     }
                     break;
                 case CMD_SET_BATCHED_SCAN:
-                    recordBatchedScanSettings((BatchedScanSettings)message.obj);
+                    recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj);
                     break;
                 case CMD_POLL_BATCHED_SCAN:
                     handleBatchedScanPollRequest();
@@ -2960,9 +3024,7 @@
 
             mDhcpActive = false;
 
-            if (mBatchedScanSettings != null) {
-                startBatchedScan();
-            }
+            startBatchedScan();
 
             if (mOperationalMode != CONNECT_MODE) {
                 mWifiNative.disconnect();
@@ -3021,8 +3083,10 @@
                     startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     break;
                 case CMD_SET_BATCHED_SCAN:
-                    recordBatchedScanSettings((BatchedScanSettings)message.obj);
-                    startBatchedScan();
+                    if (recordBatchedScanSettings(message.arg1, message.arg2,
+                            (Bundle)message.obj)) {
+                        startBatchedScan();
+                    }
                     break;
                 case CMD_SET_COUNTRY_CODE:
                     String country = (String) message.obj;
@@ -3160,9 +3224,7 @@
             updateBatteryWorkSource(null);
             mScanResults = new ArrayList<ScanResult>();
 
-            if (mBatchedScanSettings != null) {
-                stopBatchedScan();
-            }
+            stopBatchedScan();
 
             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);