Merge "Revert "Expose new API for querying whether a certificate was user added.""
diff --git a/Android.mk b/Android.mk
index bcab276..8b137ea 100644
--- a/Android.mk
+++ b/Android.mk
@@ -255,15 +255,22 @@
 	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 \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
+	telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
+	telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
+	telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl \
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
@@ -622,9 +629,9 @@
 		-samplecode $(sample_dir)/BasicSyncAdapter \
  		            samples/BasicSyncAdapter "" \
 		-samplecode $(sample_dir)/StorageClient \
- 		            samples/StorageClient "" 
-#		-samplecode $(sample_dir)/StorageProvider \
-# 		            samples/StorageProvider "" 
+ 		            samples/StorageClient "" \
+		-samplecode $(sample_dir)/StorageProvider \
+ 		            samples/StorageProvider ""
 #       -samplecode $(sample_dir)/AndroidBeamDemo \
 # 		            samples/AndroidBeamDemo "Android Beam Demo" \
 # 		-samplecode $(sample_dir)/ApiDemos \
diff --git a/api/current.txt b/api/current.txt
index 745b33d93..2845af1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1207,6 +1207,8 @@
     field public static final int windowBackground = 16842836; // 0x1010054
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
     field public static final int windowContentOverlay = 16842841; // 0x1010059
+    field public static final int windowContentTransitionManager = 16843765; // 0x10103f5
+    field public static final int windowContentTransitions = 16843764; // 0x10103f4
     field public static final int windowDisablePreview = 16843298; // 0x1010222
     field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
     field public static final int windowEnterAnimation = 16842932; // 0x10100b4
@@ -1810,6 +1812,7 @@
     field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
     field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
     field public static final int Theme_Panel = 16973913; // 0x1030059
+    field public static final int Theme_Quantum = 16974318; // 0x10301ee
     field public static final int Theme_Translucent = 16973839; // 0x103000f
     field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
     field public static final int Theme_Translucent_NoTitleBar_Fullscreen = 16973841; // 0x1030011
@@ -2935,7 +2938,7 @@
     method public final void setSecondaryProgress(int);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
-    method public void setTitleColor(int);
+    method public deprecated void setTitleColor(int);
     method public void setVisible(boolean);
     method public final void setVolumeControlStream(int);
     method public boolean shouldUpRecreateTask(android.content.Intent);
@@ -7634,11 +7637,9 @@
     ctor public ColorStateList(int[][], int[]);
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
-    method public int getColorAt(int);
     method public int getColorForState(int[], int);
-    method public int getCount();
     method public int getDefaultColor();
-    method public int[] getStateSpecAt(int);
+    method public boolean isOpaque();
     method public boolean isStateful();
     method public static android.content.res.ColorStateList valueOf(int);
     method public android.content.res.ColorStateList withAlpha(int);
@@ -10284,6 +10285,7 @@
     method public void draw(android.graphics.Canvas);
     method public int getOpacity();
     method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
+    method public boolean onStateChange(int[]);
     method public void setAlpha(int);
     method public void setColor(int);
     method public void setColor(android.content.res.ColorStateList);
@@ -10298,7 +10300,9 @@
     method public void setShape(int);
     method public void setSize(int, int);
     method public void setStroke(int, int);
+    method public void setStroke(int, android.content.res.ColorStateList);
     method public void setStroke(int, int, float, float);
+    method public void setStroke(int, android.content.res.ColorStateList, float, float);
     method public void setUseLevel(boolean);
     field public static final int LINE = 2; // 0x2
     field public static final int LINEAR_GRADIENT = 0; // 0x0
@@ -11314,10 +11318,6 @@
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TIMESTAMP;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_IDS;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_LANDMARKS;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_RECTANGLES;
-    field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_SCORES;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_PREDICTED_COLOR_GAINS;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_PREDICTED_COLOR_TRANSFORM;
@@ -24135,6 +24135,32 @@
     field public static final int SIM_STATE_UNKNOWN = 0; // 0x0
   }
 
+  public class ThirdPartyCallListener {
+    ctor public ThirdPartyCallListener(com.android.internal.telephony.IThirdPartyCallListener);
+    method public void onCallEnded(int);
+    method public void onCallEstablished();
+    method public void onCallProviderAttached(android.telephony.ThirdPartyCallProvider);
+    method public void onRingingStarted();
+    field public static final int CALL_END_INCOMING_MISSED = 2; // 0x2
+    field public static final int CALL_END_NORMAL = 1; // 0x1
+    field public static final int CALL_END_OTHER = 3; // 0x3
+  }
+
+  public class ThirdPartyCallProvider {
+    ctor public ThirdPartyCallProvider();
+    method public void hangup();
+    method public void incomingCallAccept();
+    method public void mute(boolean);
+    method public void sendDtmf(char);
+  }
+
+  public class ThirdPartyCallService {
+    ctor public ThirdPartyCallService();
+    method public android.os.IBinder getBinder();
+    method public void incomingCallAttach(android.telephony.ThirdPartyCallListener, java.lang.String);
+    method public void outgoingCallInitiate(android.telephony.ThirdPartyCallListener, java.lang.String);
+  }
+
 }
 
 package android.telephony.cdma {
@@ -26254,7 +26280,8 @@
 
   public final class Scene {
     ctor public Scene(android.view.ViewGroup);
-    ctor public Scene(android.view.ViewGroup, android.view.ViewGroup);
+    ctor public Scene(android.view.ViewGroup, android.view.View);
+    ctor public deprecated Scene(android.view.ViewGroup, android.view.ViewGroup);
     method public void enter();
     method public void exit();
     method public static android.transition.Scene getSceneForLayout(android.view.ViewGroup, int, android.content.Context);
@@ -29293,7 +29320,7 @@
     method public void setLogo(int);
     method public void setSoftInputMode(int);
     method public abstract void setTitle(java.lang.CharSequence);
-    method public abstract void setTitleColor(int);
+    method public abstract deprecated void setTitleColor(int);
     method public void setType(int);
     method public void setUiOptions(int);
     method public void setUiOptions(int, int);
@@ -29314,6 +29341,7 @@
     field public static final int FEATURE_ACTION_BAR = 8; // 0x8
     field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
     field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+    field public static final int FEATURE_CONTENT_TRANSITIONS = 11; // 0xb
     field public static final int FEATURE_CONTEXT_MENU = 6; // 0x6
     field public static final int FEATURE_CUSTOM_TITLE = 7; // 0x7
     field public static final int FEATURE_INDETERMINATE_PROGRESS = 5; // 0x5
@@ -29664,6 +29692,9 @@
     method public boolean performAction(int, android.os.Bundle);
     method public void recycle();
     method public boolean refresh();
+    method public void removeAction(int);
+    method public boolean removeChild(android.view.View);
+    method public boolean removeChild(android.view.View, int);
     method public void setAccessibilityFocused(boolean);
     method public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
@@ -33530,6 +33561,24 @@
 
 }
 
+package com.android.internal.telephony {
+
+  public abstract interface IThirdPartyCallListener implements android.os.IInterface {
+    method public abstract void onCallEnded(int) throws android.os.RemoteException;
+    method public abstract void onCallEstablished() throws android.os.RemoteException;
+    method public abstract void onCallProviderAttached(com.android.internal.telephony.IThirdPartyCallProvider) throws android.os.RemoteException;
+    method public abstract void onRingingStarted() throws android.os.RemoteException;
+  }
+
+  public abstract interface IThirdPartyCallProvider implements android.os.IInterface {
+    method public abstract void hangup() throws android.os.RemoteException;
+    method public abstract void incomingCallAccept() throws android.os.RemoteException;
+    method public abstract void mute(boolean) throws android.os.RemoteException;
+    method public abstract void sendDtmf(char) throws android.os.RemoteException;
+  }
+
+}
+
 package com.android.internal.util {
 
   public abstract interface Predicate {
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/Activity.java b/core/java/android/app/Activity.java
index 8628ff7..d34b05d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4598,6 +4598,17 @@
         setTitle(getText(titleId));
     }
 
+    /**
+     * Change the color of the title associated with this activity.
+     * <p>
+     * This method is deprecated starting in API Level 11 and replaced by action
+     * bar styles. For information on styling the Action Bar, read the <a
+     * href="{@docRoot} guide/topics/ui/actionbar.html">Action Bar</a> developer
+     * guide.
+     *
+     * @deprecated Use action bar styles instead.
+     */
+    @Deprecated
     public void setTitleColor(int textColor) {
         mTitleColor = textColor;
         onTitleChanged(mTitle, textColor);
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/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 87b1e24..44f6859 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -90,6 +90,35 @@
      */
     public static final String KEY_ANIM_START_LISTENER = "android:animStartListener";
 
+    /**
+     * A string array of names for the destination scene. This defines an API in the same
+     * way that intent action or extra names do and should follow a similar convention:
+     * "com.example.scene.FOO"
+     *
+     * @hide
+     */
+    public static final String KEY_DEST_SCENE_NAMES = "android:destSceneNames";
+
+    /**
+     * A string indicating the destination scene name that was chosen by the target.
+     * Used by {@link OnSceneTransitionStartedListener}.
+     * @hide
+     */
+    public static final String KEY_DEST_SCENE_NAME_CHOSEN = "android:destSceneNameChosen";
+
+    /**
+     * Callback for when scene transition is started.
+     * @hide
+     */
+    public static final String KEY_SCENE_TRANSITION_START_LISTENER =
+            "android:sceneTransitionStartListener";
+
+    /**
+     * Arguments for the scene transition about to begin.
+     * @hide
+     */
+    public static final String KEY_SCENE_TRANSITION_ARGS = "android:sceneTransitionArgs";
+
     /** @hide */
     public static final int ANIM_NONE = 0;
     /** @hide */
@@ -100,6 +129,8 @@
     public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
     /** @hide */
     public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
+    /** @hide */
+    public static final int ANIM_SCENE_TRANSITION = 5;
 
     private String mPackageName;
     private int mAnimationType = ANIM_NONE;
@@ -110,7 +141,10 @@
     private int mStartY;
     private int mStartWidth;
     private int mStartHeight;
+    private String[] mDestSceneNames;
+    private Bundle mTransitionArgs;
     private IRemoteCallback mAnimationStartedListener;
+    private IRemoteCallback mSceneTransitionStartedListener;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -156,11 +190,12 @@
         opts.mAnimationType = ANIM_CUSTOM;
         opts.mCustomEnterResId = enterResId;
         opts.mCustomExitResId = exitResId;
-        opts.setListener(handler, listener);
+        opts.setOnAnimationStartedListener(handler, listener);
         return opts;
     }
 
-    private void setListener(Handler handler, OnAnimationStartedListener listener) {
+    private void setOnAnimationStartedListener(Handler handler,
+            OnAnimationStartedListener listener) {
         if (listener != null) {
             final Handler h = handler;
             final OnAnimationStartedListener finalListener = listener;
@@ -176,6 +211,24 @@
         }
     }
 
+    private void setOnSceneTransitionStartedListener(Handler handler,
+            OnSceneTransitionStartedListener listener) {
+        if (listener != null) {
+            final Handler h = handler;
+            final OnSceneTransitionStartedListener l = listener;
+            mSceneTransitionStartedListener = new IRemoteCallback.Stub() {
+                @Override public void sendResult(final Bundle data) throws RemoteException {
+                    h.post(new Runnable() {
+                        public void run() {
+                            l.onSceneTransitionStarted(data != null ?
+                                    data.getString(KEY_DEST_SCENE_NAME_CHOSEN) : null);
+                        }
+                    });
+                }
+            };
+        }
+    }
+
     /**
      * Callback for use with {@link ActivityOptions#makeThumbnailScaleUpAnimation}
      * to find out when the given animation has started running.
@@ -186,6 +239,15 @@
     }
 
     /**
+     * Callback for use with {@link ActivityOptions#makeSceneTransitionAnimation}
+     * to find out when a transition is about to begin.
+     * @hide
+     */
+    public interface OnSceneTransitionStartedListener {
+        void onSceneTransitionStarted(String destSceneName);
+    }
+
+    /**
      * Create an ActivityOptions specifying an animation where the new
      * activity is scaled from a small originating area of the screen to
      * its final full representation.
@@ -298,7 +360,23 @@
         source.getLocationOnScreen(pts);
         opts.mStartX = pts[0] + startX;
         opts.mStartY = pts[1] + startY;
-        opts.setListener(source.getHandler(), listener);
+        opts.setOnAnimationStartedListener(source.getHandler(), listener);
+        return opts;
+    }
+
+    /**
+     * Create an ActivityOptions specifying an animation where an activity window is asked
+     * to perform animations within the window content.
+     *
+     * @hide
+     */
+    public static ActivityOptions makeSceneTransitionAnimation(String[] destSceneNames,
+            Bundle args, OnSceneTransitionStartedListener listener, Handler handler) {
+        ActivityOptions opts = new ActivityOptions();
+        opts.mAnimationType = ANIM_SCENE_TRANSITION;
+        opts.mDestSceneNames = destSceneNames;
+        opts.mTransitionArgs = args;
+        opts.setOnSceneTransitionStartedListener(handler, listener);
         return opts;
     }
 
@@ -309,23 +387,36 @@
     public ActivityOptions(Bundle opts) {
         mPackageName = opts.getString(KEY_PACKAGE_NAME);
         mAnimationType = opts.getInt(KEY_ANIM_TYPE);
-        if (mAnimationType == ANIM_CUSTOM) {
-            mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
-            mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
-            mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
-                    opts.getIBinder(KEY_ANIM_START_LISTENER));
-        } else if (mAnimationType == ANIM_SCALE_UP) {
-            mStartX = opts.getInt(KEY_ANIM_START_X, 0);
-            mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
-            mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
-            mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
-        } else if (mAnimationType == ANIM_THUMBNAIL_SCALE_UP ||
-                mAnimationType == ANIM_THUMBNAIL_SCALE_DOWN) {
-            mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
-            mStartX = opts.getInt(KEY_ANIM_START_X, 0);
-            mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
-            mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
-                    opts.getIBinder(KEY_ANIM_START_LISTENER));
+        switch (mAnimationType) {
+            case ANIM_CUSTOM:
+                mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
+                mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
+                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
+                        opts.getBinder(KEY_ANIM_START_LISTENER));
+                break;
+
+            case ANIM_SCALE_UP:
+                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
+                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
+                mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
+                mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
+                break;
+
+            case ANIM_THUMBNAIL_SCALE_UP:
+            case ANIM_THUMBNAIL_SCALE_DOWN:
+                mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
+                mStartX = opts.getInt(KEY_ANIM_START_X, 0);
+                mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
+                mAnimationStartedListener = IRemoteCallback.Stub.asInterface(
+                        opts.getBinder(KEY_ANIM_START_LISTENER));
+                break;
+
+            case ANIM_SCENE_TRANSITION:
+                mDestSceneNames = opts.getStringArray(KEY_DEST_SCENE_NAMES);
+                mTransitionArgs = opts.getBundle(KEY_SCENE_TRANSITION_ARGS);
+                mSceneTransitionStartedListener = IRemoteCallback.Stub.asInterface(
+                        opts.getBinder(KEY_SCENE_TRANSITION_START_LISTENER));
+                break;
         }
     }
 
@@ -375,11 +466,26 @@
     }
 
     /** @hide */
+    public String[] getDestSceneNames() {
+        return mDestSceneNames;
+    }
+
+    /** @hide */
+    public Bundle getSceneTransitionArgs() {
+        return mTransitionArgs;
+    }
+
+    /** @hide */
     public IRemoteCallback getOnAnimationStartListener() {
         return mAnimationStartedListener;
     }
 
     /** @hide */
+    public IRemoteCallback getOnSceneTransitionStartedListener() {
+        return mSceneTransitionStartedListener;
+    }
+
+    /** @hide */
     public void abort() {
         if (mAnimationStartedListener != null) {
             try {
@@ -411,13 +517,16 @@
                 mCustomEnterResId = otherOptions.mCustomEnterResId;
                 mCustomExitResId = otherOptions.mCustomExitResId;
                 mThumbnail = null;
-                if (otherOptions.mAnimationStartedListener != null) {
+                if (mAnimationStartedListener != null) {
                     try {
-                        otherOptions.mAnimationStartedListener.sendResult(null);
+                        mAnimationStartedListener.sendResult(null);
                     } catch (RemoteException e) {
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
+                mSceneTransitionStartedListener = null;
+                mTransitionArgs = null;
+                mDestSceneNames = null;
                 break;
             case ANIM_SCALE_UP:
                 mAnimationType = otherOptions.mAnimationType;
@@ -425,13 +534,16 @@
                 mStartY = otherOptions.mStartY;
                 mStartWidth = otherOptions.mStartWidth;
                 mStartHeight = otherOptions.mStartHeight;
-                if (otherOptions.mAnimationStartedListener != null) {
+                if (mAnimationStartedListener != null) {
                     try {
-                        otherOptions.mAnimationStartedListener.sendResult(null);
+                        mAnimationStartedListener.sendResult(null);
                     } catch (RemoteException e) {
                     }
                 }
                 mAnimationStartedListener = null;
+                mSceneTransitionStartedListener = null;
+                mTransitionArgs = null;
+                mDestSceneNames = null;
                 break;
             case ANIM_THUMBNAIL_SCALE_UP:
             case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -439,13 +551,28 @@
                 mThumbnail = otherOptions.mThumbnail;
                 mStartX = otherOptions.mStartX;
                 mStartY = otherOptions.mStartY;
-                if (otherOptions.mAnimationStartedListener != null) {
+                if (mAnimationStartedListener != null) {
                     try {
-                        otherOptions.mAnimationStartedListener.sendResult(null);
+                        mAnimationStartedListener.sendResult(null);
                     } catch (RemoteException e) {
                     }
                 }
                 mAnimationStartedListener = otherOptions.mAnimationStartedListener;
+                mSceneTransitionStartedListener = null;
+                mTransitionArgs = null;
+                mDestSceneNames = null;
+                break;
+            case ANIM_SCENE_TRANSITION:
+                mAnimationType = otherOptions.mAnimationType;
+                if (mSceneTransitionStartedListener != null) {
+                    try {
+                        mSceneTransitionStartedListener.sendResult(null);
+                    } catch (RemoteException e) {
+                    }
+                }
+                mSceneTransitionStartedListener = otherOptions.mSceneTransitionStartedListener;
+                mDestSceneNames = otherOptions.mDestSceneNames;
+                mAnimationStartedListener = null;
                 break;
         }
     }
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index b741cc5..2ed8b0f 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1011,15 +1011,15 @@
     }
 
     /**
-     * Returns {@link Uri} for the given downloaded file id, if the file is
-     * downloaded successfully. otherwise, null is returned.
+     * Returns the {@link Uri} of the given downloaded file id, if the file is
+     * downloaded successfully. Otherwise, null is returned.
      *<p>
      * If the specified downloaded file is in external storage (for example, /sdcard dir),
      * then it is assumed to be safe for anyone to read and the returned {@link Uri} corresponds
      * to the filepath on sdcard.
      *
      * @param id the id of the downloaded file.
-     * @return the {@link Uri} for the given downloaded file id, if download was successful. null
+     * @return the {@link Uri} of the given downloaded file id, if download was successful. null
      * otherwise.
      */
     public Uri getUriForDownloadedFile(long id) {
@@ -1064,15 +1064,11 @@
     }
 
     /**
-     * Returns {@link Uri} for the given downloaded file id, if the file is
-     * downloaded successfully. otherwise, null is returned.
-     *<p>
-     * If the specified downloaded file is in external storage (for example, /sdcard dir),
-     * then it is assumed to be safe for anyone to read and the returned {@link Uri} corresponds
-     * to the filepath on sdcard.
+     * Returns the media type of the given downloaded file id, if the file was
+     * downloaded successfully. Otherwise, null is returned.
      *
      * @param id the id of the downloaded file.
-     * @return the {@link Uri} for the given downloaded file id, if download was successful. null
+     * @return the media type of the given downloaded file id, if download was successful. null
      * otherwise.
      */
     public String getMimeTypeForDownloadedFile(long id) {
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3efd3c0..181eb63 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -71,4 +71,14 @@
      * Returns the desired minimum height for the wallpaper.
      */
     int getHeightHint();
+
+    /**
+     * Returns the name of the wallpaper. Private API.
+     */
+    String getName();
+
+    /**
+     * Informs the service that wallpaper settings have been restored. Private API.
+     */
+    void settingsRestored();
 }
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 2464e35..fa2813e 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
     };
@@ -83,6 +81,7 @@
         super(context, attrs, defStyleAttr, defStyleRes);
 
         mRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        mCallback = new MediaRouterCallback();
 
         final TypedArray a = context.obtainStyledAttributes(attrs,
                 com.android.internal.R.styleable.MediaRouteButton, defStyleAttr, defStyleRes);
@@ -103,19 +102,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
@@ -125,29 +192,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
@@ -188,85 +233,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);
@@ -294,6 +263,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;
@@ -302,12 +286,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);
         }
@@ -316,19 +304,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();
     }
 
@@ -391,93 +382,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 61b11c2..9a8e6b6 100644
--- a/core/java/android/content/SyncInfo.java
+++ b/core/java/android/content/SyncInfo.java
@@ -65,6 +65,15 @@
     }
 
     /** @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;
+        this.service = other.service;
+    }
+
+    /** @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/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index fe9305e..431226a 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -16,6 +16,7 @@
 
 package android.content.res;
 
+import android.graphics.Color;
 import com.android.internal.util.ArrayUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -259,7 +260,17 @@
     public boolean isStateful() {
         return mStateSpecs.length > 1;
     }
-    
+
+    public boolean isOpaque() {
+        final int n = mColors.length;
+        for (int i = 0; i < n; i++) {
+            if (Color.alpha(mColors[i]) != 0xFF) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * Return the color associated with the given set of {@link android.view.View} states.
      *
@@ -281,31 +292,6 @@
     }
 
     /**
-     * @return the number of state spec to color mappings in the list
-     * @see #getColorAt(int)
-     * @see #getStateSpecAt(int)
-     */
-    public int getCount() {
-        return mColors.length;
-    }
-
-    /**
-     * @return the state spec at the specified index in the list
-     * @see #getCount()
-     */
-    public int[] getStateSpecAt(int index) {
-        return mStateSpecs[index];
-    }
-
-    /**
-     * @return the color at the specified index in the list
-     * @see #getCount()
-     */
-    public int getColorAt(int index) {
-        return mColors[index];
-    }
-
-    /**
      * Return the default color in this {@link ColorStateList}.
      *
      * @return the default color in this {@link ColorStateList}.
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/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1d6ff7d..5d0bb33 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -168,7 +168,7 @@
 
             Key lhs = (Key) o;
 
-            return mName.equals(lhs.mName);
+            return mName.equals(lhs.mName) && mType.equals(lhs.mType);
         }
 
         /**
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index dbd0457..7810f24 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).
@@ -758,6 +784,8 @@
      * <p>
      * Only available if faceDetectMode == FULL
      * </p>
+     *
+     * @hide
      */
     public static final Key<int[]> STATISTICS_FACE_IDS =
             new Key<int[]>("android.statistics.faceIds", int[].class);
@@ -770,6 +798,8 @@
      * <p>
      * Only available if faceDetectMode == FULL
      * </p>
+     *
+     * @hide
      */
     public static final Key<int[]> STATISTICS_FACE_LANDMARKS =
             new Key<int[]>("android.statistics.faceLandmarks", int[].class);
@@ -782,6 +812,8 @@
      * <p>
      * Only available if faceDetectMode != OFF
      * </p>
+     *
+     * @hide
      */
     public static final Key<android.graphics.Rect[]> STATISTICS_FACE_RECTANGLES =
             new Key<android.graphics.Rect[]>("android.statistics.faceRectangles", android.graphics.Rect[].class);
@@ -795,6 +827,8 @@
      * Only available if faceDetectMode != OFF. The value should be
      * meaningful (for example, setting 100 at all times is illegal).
      * </p>
+     *
+     * @hide
      */
     public static final Key<byte[]> STATISTICS_FACE_SCORES =
             new Key<byte[]>("android.statistics.faceScores", byte[].class);
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index c5d0999..40586f0 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -19,27 +19,24 @@
 import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
 
 import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
-import android.os.IBinder;
-import android.os.RemoteException;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Surface;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
-import java.util.Stack;
 
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -49,6 +46,8 @@
     private final String TAG;
     private final boolean DEBUG;
 
+    private static final int REQUEST_ID_NONE = -1;
+
     // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
     private ICameraDeviceUser mRemoteDevice;
 
@@ -63,7 +62,8 @@
     private final SparseArray<CaptureListenerHolder> mCaptureListenerMap =
             new SparseArray<CaptureListenerHolder>();
 
-    private final Stack<Integer> mRepeatingRequestIdStack = new Stack<Integer>();
+    private int mRepeatingRequestId = REQUEST_ID_NONE;
+    private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
     // Map stream IDs to Surfaces
     private final SparseArray<Surface> mConfiguredOutputs = new SparseArray<Surface>();
 
@@ -186,7 +186,7 @@
             stopRepeating();
 
             try {
-                mRemoteDevice.waitUntilIdle();
+                waitUntilIdle();
 
                 // TODO: mRemoteDevice.beginConfigure
                 // Delete all streams first (to free up HW resources)
@@ -279,6 +279,10 @@
             checkIfCameraClosed();
             int requestId;
 
+            if (repeating) {
+                stopRepeating();
+            }
+
             try {
                 requestId = mRemoteDevice.submitRequest(request, repeating);
             } catch (CameraRuntimeException e) {
@@ -293,7 +297,7 @@
             }
 
             if (repeating) {
-                mRepeatingRequestIdStack.add(requestId);
+                mRepeatingRequestId = requestId;
             }
 
             if (mIdle) {
@@ -327,8 +331,13 @@
 
         synchronized (mLock) {
             checkIfCameraClosed();
-            while (!mRepeatingRequestIdStack.isEmpty()) {
-                int requestId = mRepeatingRequestIdStack.pop();
+            if (mRepeatingRequestId != REQUEST_ID_NONE) {
+
+                int requestId = mRepeatingRequestId;
+                mRepeatingRequestId = REQUEST_ID_NONE;
+
+                // Queue for deletion after in-flight requests finish
+                mRepeatingRequestIdDeletedList.add(requestId);
 
                 try {
                     mRemoteDevice.cancelRequest(requestId);
@@ -347,7 +356,7 @@
 
         synchronized (mLock) {
             checkIfCameraClosed();
-            if (!mRepeatingRequestIdStack.isEmpty()) {
+            if (mRepeatingRequestId != REQUEST_ID_NONE) {
                 throw new IllegalStateException("Active repeating request ongoing");
             }
 
@@ -359,6 +368,10 @@
                 // impossible
                 return;
             }
+
+            mRepeatingRequestId = REQUEST_ID_NONE;
+            mRepeatingRequestIdDeletedList.clear();
+            mCaptureListenerMap.clear();
         }
     }
 
@@ -564,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..
@@ -572,13 +588,28 @@
                 holder = CameraDevice.this.mCaptureListenerMap.get(requestId);
 
                 // Clean up listener once we no longer expect to see it.
-
-                // TODO: how to handle repeating listeners?
-                // we probably want cancelRequest to return # of times it already enqueued and
-                // keep a counter.
-                if (holder != null && !holder.isRepeating()) {
+                if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) {
                     CameraDevice.this.mCaptureListenerMap.remove(requestId);
                 }
+
+                // TODO: add 'capture sequence completed' callback to the
+                // service, and clean up repeating requests there instead.
+
+                // 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() && !quirkIsPartialResult
+                        && mRepeatingRequestIdDeletedList.size() > 0) {
+                    Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator();
+                    while (iter.hasNext()) {
+                        int deletedRequestId = iter.next();
+                        if (deletedRequestId < requestId) {
+                            CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId);
+                            iter.remove();
+                        }
+                    }
+                }
+
             }
 
             // Check if we have a listener for this
@@ -591,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()){
@@ -602,7 +650,10 @@
                                 resultAsCapture);
                         }
                     }
-                });
+                };
+            }
+
+            holder.getHandler().post(resultDispatch);
         }
 
     }
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 072c5bb..2ddcb14 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -448,7 +448,7 @@
         } else if (key.equals(CaptureResult.STATISTICS_FACES)) {
             return (T) getFaces();
         } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
-            return (T) fixFaceRectangles();
+            return (T) getFaceRectangles();
         }
 
         // For other keys, get() falls back to getBase()
@@ -457,12 +457,15 @@
 
     private int[] getAvailableFormats() {
         int[] availableFormats = getBase(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
-        for (int i = 0; i < availableFormats.length; i++) {
-            // JPEG has different value between native and managed side, need override.
-            if (availableFormats[i] == NATIVE_JPEG_FORMAT) {
-                availableFormats[i] = ImageFormat.JPEG;
+        if (availableFormats != null) {
+            for (int i = 0; i < availableFormats.length; i++) {
+                // JPEG has different value between native and managed side, need override.
+                if (availableFormats[i] == NATIVE_JPEG_FORMAT) {
+                    availableFormats[i] = ImageFormat.JPEG;
+                }
             }
         }
+
         return availableFormats;
     }
 
@@ -550,7 +553,7 @@
     // (left, top, width, height) at the native level, so the normal Rect
     // conversion that does (l, t, w, h) -> (l, t, r, b) is unnecessary. Undo
     // that conversion here for just the faces.
-    private Rect[] fixFaceRectangles() {
+    private Rect[] getFaceRectangles() {
         Rect[] faceRectangles = getBase(CaptureResult.STATISTICS_FACE_RECTANGLES);
         if (faceRectangles == null) return null;
 
@@ -590,6 +593,8 @@
     private <T> boolean setOverride(Key<T> key, T value) {
         if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)) {
             return setAvailableFormats((int[]) value);
+        } else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
+            return setFaceRectangles((Rect[]) value);
         }
 
         // For other keys, set() falls back to setBase().
@@ -615,6 +620,36 @@
         return true;
     }
 
+    /**
+     * Convert Face Rectangles from managed side to native side as they have different definitions.
+     * <p>
+     * Managed side face rectangles are defined as: left, top, width, height.
+     * Native side face rectangles are defined as: left, top, right, bottom.
+     * The input face rectangle need to be converted to native side definition when set is called.
+     * </p>
+     *
+     * @param faceRects Input face rectangles.
+     * @return true if face rectangles can be set successfully. Otherwise, Let the caller
+     *             (setBase) to handle it appropriately.
+     */
+    private boolean setFaceRectangles(Rect[] faceRects) {
+        if (faceRects == null) {
+            return false;
+        }
+
+        Rect[] newFaceRects = new Rect[faceRects.length];
+        for (int i = 0; i < newFaceRects.length; i++) {
+            newFaceRects[i] = new Rect(
+                    faceRects[i].left,
+                    faceRects[i].top,
+                    faceRects[i].right + faceRects[i].left,
+                    faceRects[i].bottom + faceRects[i].top);
+        }
+
+        setBase(CaptureResult.STATISTICS_FACE_RECTANGLES, newFaceRects);
+        return true;
+    }
+
     private long mMetadataPtr; // native CameraMetadata*
 
     private native long nativeAllocate();
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/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 2b58818..de481cf 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -269,6 +269,7 @@
             "urn:epc:pat:", // 0x20
             "urn:epc:raw:", // 0x21
             "urn:epc:", // 0x22
+            "urn:nfc:", // 0x23
     };
 
     private static final int MAX_PAYLOAD_SIZE = 10 * (1 << 20);  // 10 MB payload limit
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index bc98a0b..b1a9ea30 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
@@ -844,12 +854,13 @@
     public static final int DATA_CONNECTION_EVDO_B = 12;
     public static final int DATA_CONNECTION_LTE = 13;
     public static final int DATA_CONNECTION_EHRPD = 14;
-    public static final int DATA_CONNECTION_OTHER = 15;
+    public static final int DATA_CONNECTION_HSPAP = 15;
+    public static final int DATA_CONNECTION_OTHER = 16;
 
     static final String[] DATA_CONNECTION_NAMES = {
         "none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A",
         "1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte",
-        "ehrpd", "other"
+        "ehrpd", "hspap", "other"
     };
     
     public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1;
@@ -2080,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/os/Bundle.java b/core/java/android/os/Bundle.java
index f9c1d31..af57507 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -380,7 +380,7 @@
                         SparseArray<? extends Parcelable> array =
                                 (SparseArray<? extends Parcelable>) obj;
                         for (int n = array.size() - 1; n >= 0; n--) {
-                            if ((array.get(n).describeContents()
+                            if ((array.valueAt(n).describeContents()
                                     & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
                                 fdFound = true;
                                 break;
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index bb3d296..3249bcb 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -22,9 +22,12 @@
  * Writes trace events to the system trace buffer.  These trace events can be
  * collected and visualized using the Systrace tool.
  *
- * This tracing mechanism is independent of the method tracing mechanism
+ * <p>This tracing mechanism is independent of the method tracing mechanism
  * offered by {@link Debug#startMethodTracing}.  In particular, it enables
  * tracing of events that occur across multiple processes.
+ * <p>For information about using the Systrace tool, read <a
+ * href="{@docRoot}tools/debugging/systrace.html">Analyzing Display and Performance
+ * with Systrace</a>.
  */
 public final class Trace {
     /*
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 9abd7ef..76fccc7 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1096,11 +1096,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 2ab5a91..7ddfa87 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -33,7 +33,6 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.LayoutInflater;
@@ -125,8 +124,6 @@
         PreferenceManager.OnPreferenceTreeClickListener,
         PreferenceFragment.OnPreferenceStartFragmentCallback {
 
-    private static final String TAG = "PreferenceActivity";
-
     // Constants for state save/restore
     private static final String HEADERS_TAG = ":android:headers";
     private static final String CUR_HEADER_TAG = ":android:cur_header";
@@ -524,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);
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 25d6f5b..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;
@@ -216,6 +217,8 @@
      * {@link Root#FLAG_SUPPORTS_RECENTS}. The returned documents should be
      * sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and
      * limited to only return the 64 most recently modified documents.
+     * <p>
+     * Recent documents do not support change notifications.
      *
      * @param projection list of {@link Document} columns to put into the
      *            cursor. If {@code null} all supported columns should be
@@ -250,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
@@ -360,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()
@@ -384,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/provider/Settings.java b/core/java/android/provider/Settings.java
index a960bba..0dffc17 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3252,9 +3252,14 @@
 
         /**
          * A 64-bit number (as a hex string) that is randomly
-         * generated on the device's first boot and should remain
-         * constant for the lifetime of the device.  (The value may
-         * change if a factory reset is performed on the device.)
+         * generated when the user first sets up the device and should remain
+         * constant for the lifetime of the user's device. The value may
+         * change if a factory reset is performed on the device.
+         * <p class="note"><strong>Note:</strong> When a device has <a
+         * href="{@docRoot}about/versions/android-4.2.html#MultipleUsers">multiple users</a>
+         * (available on certain devices running Android 4.2 or higher), each user appears as a
+         * completely separate device, so the {@code ANDROID_ID} value is unique to each
+         * user.</p>
          */
         public static final String ANDROID_ID = "android_id";
 
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/transition/Scene.java b/core/java/android/transition/Scene.java
index e1f1896..4267a65 100644
--- a/core/java/android/transition/Scene.java
+++ b/core/java/android/transition/Scene.java
@@ -34,7 +34,7 @@
     private Context mContext;
     private int mLayoutId = -1;
     private ViewGroup mSceneRoot;
-    private ViewGroup mLayout; // alternative to layoutId
+    private View mLayout; // alternative to layoutId
     Runnable mEnterAction, mExitAction;
 
     /**
@@ -114,6 +114,15 @@
      * @param layout The view hierarchy of this scene, added as a child
      * of sceneRoot when this scene is entered.
      */
+    public Scene(ViewGroup sceneRoot, View layout) {
+        mSceneRoot = sceneRoot;
+        mLayout = layout;
+    }
+
+    /**
+     * @deprecated use {@link #Scene(ViewGroup, View)}.
+     */
+    @Deprecated
     public Scene(ViewGroup sceneRoot, ViewGroup layout) {
         mSceneRoot = sceneRoot;
         mLayout = layout;
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
new file mode 100644
index 0000000..7d42063
--- /dev/null
+++ b/core/java/android/util/LongArray.java
@@ -0,0 +1,160 @@
+/*
+ * 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.util;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Implements a growing array of long primitives.
+ *
+ * @hide
+ */
+public class LongArray implements Cloneable {
+    private static final int MIN_CAPACITY_INCREMENT = 12;
+
+    private long[] mValues;
+    private int mSize;
+
+    /**
+     * Creates an empty LongArray with the default initial capacity.
+     */
+    public LongArray() {
+        this(10);
+    }
+
+    /**
+     * Creates an empty LongArray with the specified initial capacity.
+     */
+    public LongArray(int initialCapacity) {
+        if (initialCapacity == 0) {
+            mValues = ContainerHelpers.EMPTY_LONGS;
+        } else {
+            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
+            mValues = new long[initialCapacity];
+        }
+        mSize = 0;
+    }
+
+    /**
+     * Appends the specified value to the end of this array.
+     */
+    public void add(long value) {
+        add(mSize, value);
+    }
+
+    /**
+     * Inserts a value at the specified position in this array.
+     *
+     * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt; size()
+     */
+    public void add(int index, long value) {
+        if (index < 0 || index > mSize) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        ensureCapacity(1);
+
+        if (mSize - index != 0) {
+            System.arraycopy(mValues, index, mValues, index + 1, mSize - index);
+        }
+
+        mValues[index] = value;
+        mSize++;
+    }
+
+    /**
+     * Adds the values in the specified array to this array.
+     */
+    public void addAll(LongArray values) {
+        final int count = values.mSize;
+        ensureCapacity(count);
+
+        System.arraycopy(mValues, mSize, values.mValues, 0, count);
+        mSize += count;
+    }
+
+    /**
+     * Ensures capacity to append at least <code>count</code> values.
+     */
+    private void ensureCapacity(int count) {
+        final int currentSize = mSize;
+        final int minCapacity = currentSize + count;
+        if (minCapacity >= mValues.length) {
+            final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ?
+                    MIN_CAPACITY_INCREMENT : currentSize >> 1);
+            final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity;
+            final long[] newValues = new long[ArrayUtils.idealLongArraySize(newCapacity)];
+            System.arraycopy(mValues, 0, newValues, 0, currentSize);
+            mValues = newValues;
+        }
+    }
+
+    /**
+     * Removes all values from this array.
+     */
+    public void clear() {
+        mSize = 0;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public LongArray clone() {
+        LongArray clone = null;
+        try {
+            clone = (LongArray) super.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
+    /**
+     * Returns the value at the specified position in this array.
+     */
+    public long get(int index) {
+        return mValues[index];
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified value in this
+     * array, or -1 if this array does not contain the value.
+     */
+    public int indexOf(long value) {
+        final int n = mSize;
+        for (int i = 0; i < n; i++) {
+            if (mValues[i] == value) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Removes the value at the specified index from this array.
+     */
+    public void remove(int index) {
+        System.arraycopy(mValues, index, mValues, index + 1, mSize - index);
+    }
+
+    /**
+     * Returns the number of values in this array.
+     */
+    public int size() {
+        return mSize;
+    }
+}
diff --git a/core/java/android/util/MapCollections.java b/core/java/android/util/MapCollections.java
index f4a9b0b..28b788b 100644
--- a/core/java/android/util/MapCollections.java
+++ b/core/java/android/util/MapCollections.java
@@ -97,10 +97,10 @@
             if (!mEntryValid) {
                 throw new IllegalStateException();
             }
+            colRemoveAt(mIndex);
             mIndex--;
             mEnd--;
             mEntryValid = false;
-            colRemoveAt(mIndex);
         }
 
         @Override
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 41d3700..95a13d0 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -24,6 +24,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.util.LongArray;
 import android.util.SparseLongArray;
 import android.view.View.AttachInfo;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -881,13 +882,12 @@
                 AccessibilityNodeInfo parent =
                     provider.createAccessibilityNodeInfo(parentVirtualDescendantId);
                 if (parent != null) {
-                    SparseLongArray childNodeIds = parent.getChildNodeIds();
-                    final int childCount = childNodeIds.size();
+                    final int childCount = parent.getChildCount();
                     for (int i = 0; i < childCount; i++) {
                         if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                             return;
                         }
-                        final long childNodeId = childNodeIds.get(i);
+                        final long childNodeId = parent.getChildId(i);
                         if (childNodeId != current.getSourceNodeId()) {
                             final int childVirtualDescendantId =
                                 AccessibilityNodeInfo.getVirtualDescendantId(childNodeId);
@@ -906,14 +906,13 @@
 
         private void prefetchDescendantsOfVirtualNode(AccessibilityNodeInfo root,
                 AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos) {
-            SparseLongArray childNodeIds = root.getChildNodeIds();
             final int initialOutInfosSize = outInfos.size();
-            final int childCount = childNodeIds.size();
+            final int childCount = root.getChildCount();
             for (int i = 0; i < childCount; i++) {
                 if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                     return;
                 }
-                final long childNodeId = childNodeIds.get(i);
+                final long childNodeId = root.getChildId(i);
                 AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(
                         AccessibilityNodeInfo.getVirtualDescendantId(childNodeId));
                 if (child != null) {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 27e3b08..d3f63b4 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -645,6 +645,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/DisplayList.java b/core/java/android/view/DisplayList.java
index 43fd628..623472a3 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -86,18 +86,15 @@
  *
  * <pre class="prettyprint">
  *     private void createDisplayList() {
- *         HardwareRenderer renderer = getHardwareRenderer();
- *         if (renderer != null) {
- *             mDisplayList = renderer.createDisplayList();
- *             HardwareCanvas canvas = mDisplayList.start(width, height);
- *             try {
- *                 for (Bitmap b : mBitmaps) {
- *                     canvas.drawBitmap(b, 0.0f, 0.0f, null);
- *                     canvas.translate(0.0f, b.getHeight());
- *                 }
- *             } finally {
- *                 displayList.end();
+ *         mDisplayList = DisplayList.create("MyDisplayList");
+ *         HardwareCanvas canvas = mDisplayList.start(width, height);
+ *         try {
+ *             for (Bitmap b : mBitmaps) {
+ *                 canvas.drawBitmap(b, 0.0f, 0.0f, null);
+ *                 canvas.translate(0.0f, b.getHeight());
  *             }
+ *         } finally {
+ *             displayList.end();
  *         }
  *     }
  *
@@ -177,6 +174,20 @@
     public static final int STATUS_DREW = 0x4;
 
     /**
+     * Creates a new display list that can be used to record batches of
+     * drawing operations.
+     *
+     * @param name The name of the display list, used for debugging purpose. May be null.
+     *
+     * @return A new display list.
+     *
+     * @hide
+     */
+    public static DisplayList create(String name) {
+        return new GLES20DisplayList(name);
+    }
+
+    /**
      * Starts recording the display list. All operations performed on the
      * returned canvas are recorded and stored in this display list.
      *
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
new file mode 100644
index 0000000..a195231
--- /dev/null
+++ b/core/java/android/view/GLRenderer.java
@@ -0,0 +1,1610 @@
+/*
+ * 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.view;
+
+import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_BAD_NATIVE_WINDOW;
+import static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_CONFIG_CAVEAT;
+import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
+import static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_DRAW;
+import static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_HEIGHT;
+import static javax.microedition.khronos.egl.EGL10.EGL_NONE;
+import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;
+import static javax.microedition.khronos.egl.EGL10.EGL_NO_DISPLAY;
+import static javax.microedition.khronos.egl.EGL10.EGL_NO_SURFACE;
+import static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_RENDERABLE_TYPE;
+import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLES;
+import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLE_BUFFERS;
+import static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_SUCCESS;
+import static javax.microedition.khronos.egl.EGL10.EGL_SURFACE_TYPE;
+import static javax.microedition.khronos.egl.EGL10.EGL_WIDTH;
+import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT;
+
+import android.content.ComponentCallbacks2;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.opengl.EGL14;
+import android.opengl.GLUtils;
+import android.opengl.ManagedEGLContext;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Surface.OutOfResourcesException;
+
+import com.google.android.gles_jni.EGLImpl;
+
+import java.io.PrintWriter;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+
+/**
+ * Hardware renderer using OpenGL
+ *
+ * @hide
+ */
+public class GLRenderer extends HardwareRenderer {
+    static final int SURFACE_STATE_ERROR = 0;
+    static final int SURFACE_STATE_SUCCESS = 1;
+    static final int SURFACE_STATE_UPDATED = 2;
+
+    static final int FUNCTOR_PROCESS_DELAY = 4;
+
+    /**
+     * Number of frames to profile.
+     */
+    private static final int PROFILE_MAX_FRAMES = 128;
+
+    /**
+     * Number of floats per profiled frame.
+     */
+    private static final int PROFILE_FRAME_DATA_COUNT = 3;
+
+    private static final int PROFILE_DRAW_MARGIN = 0;
+    private static final int PROFILE_DRAW_WIDTH = 3;
+    private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
+    private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
+    private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
+    private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
+    private static final int PROFILE_DRAW_DP_PER_MS = 7;
+
+    private static final String[] VISUALIZERS = {
+            PROFILE_PROPERTY_VISUALIZE_BARS,
+            PROFILE_PROPERTY_VISUALIZE_LINES
+    };
+
+    private static final String[] OVERDRAW = {
+            OVERDRAW_PROPERTY_SHOW,
+            OVERDRAW_PROPERTY_COUNT
+    };
+    private static final int OVERDRAW_TYPE_COUNT = 1;
+    private static final int GL_VERSION = 2;
+
+    static EGL10 sEgl;
+    static EGLDisplay sEglDisplay;
+    static EGLConfig sEglConfig;
+    static final Object[] sEglLock = new Object[0];
+    int mWidth = -1, mHeight = -1;
+
+    static final ThreadLocal<ManagedEGLContext> sEglContextStorage
+            = new ThreadLocal<ManagedEGLContext>();
+
+    EGLContext mEglContext;
+    Thread mEglThread;
+
+    EGLSurface mEglSurface;
+
+    GL mGl;
+    HardwareCanvas mCanvas;
+
+    String mName;
+
+    long mFrameCount;
+    Paint mDebugPaint;
+
+    static boolean sDirtyRegions;
+    static final boolean sDirtyRegionsRequested;
+    static {
+        String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        sDirtyRegions = "true".equalsIgnoreCase(dirtyProperty);
+        sDirtyRegionsRequested = sDirtyRegions;
+    }
+
+    boolean mDirtyRegionsEnabled;
+    boolean mUpdateDirtyRegions;
+
+    boolean mProfileEnabled;
+    int mProfileVisualizerType = -1;
+    float[] mProfileData;
+    ReentrantLock mProfileLock;
+    int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+
+    GraphDataProvider mDebugDataProvider;
+    float[][] mProfileShapes;
+    Paint mProfilePaint;
+
+    boolean mDebugDirtyRegions;
+    int mDebugOverdraw = -1;
+    HardwareLayer mDebugOverdrawLayer;
+    Paint mDebugOverdrawPaint;
+
+    final boolean mTranslucent;
+
+    private boolean mDestroyed;
+
+    private final Rect mRedrawClip = new Rect();
+
+    private final int[] mSurfaceSize = new int[2];
+    private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
+
+    private long mDrawDelta = Long.MAX_VALUE;
+
+    private GLES20Canvas mGlCanvas;
+
+    private DisplayMetrics mDisplayMetrics;
+
+    private static EGLSurface sPbuffer;
+    private static final Object[] sPbufferLock = new Object[0];
+
+    private static class GLRendererEglContext extends ManagedEGLContext {
+        final Handler mHandler = new Handler();
+
+        public GLRendererEglContext(EGLContext context) {
+            super(context);
+        }
+
+        @Override
+        public void onTerminate(final EGLContext eglContext) {
+            // Make sure we do this on the correct thread.
+            if (mHandler.getLooper() != Looper.myLooper()) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onTerminate(eglContext);
+                    }
+                });
+                return;
+            }
+
+            synchronized (sEglLock) {
+                if (sEgl == null) return;
+
+                if (EGLImpl.getInitCount(sEglDisplay) == 1) {
+                    usePbufferSurface(eglContext);
+                    GLES20Canvas.terminateCaches();
+
+                    sEgl.eglDestroyContext(sEglDisplay, eglContext);
+                    sEglContextStorage.set(null);
+                    sEglContextStorage.remove();
+
+                    sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
+                    sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
+                            EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+                    sEgl.eglReleaseThread();
+                    sEgl.eglTerminate(sEglDisplay);
+
+                    sEgl = null;
+                    sEglDisplay = null;
+                    sEglConfig = null;
+                    sPbuffer = null;
+                }
+            }
+        }
+    }
+
+    HardwareCanvas createCanvas() {
+        return mGlCanvas = new GLES20Canvas(mTranslucent);
+    }
+
+    ManagedEGLContext createManagedContext(EGLContext eglContext) {
+        return new GLRendererEglContext(mEglContext);
+    }
+
+    int[] getConfig(boolean dirtyRegions) {
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        final int stencilSize = GLES20Canvas.getStencilSize();
+        final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+
+        return new int[] {
+                EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+                EGL_RED_SIZE, 8,
+                EGL_GREEN_SIZE, 8,
+                EGL_BLUE_SIZE, 8,
+                EGL_ALPHA_SIZE, 8,
+                EGL_DEPTH_SIZE, 0,
+                EGL_CONFIG_CAVEAT, EGL_NONE,
+                EGL_STENCIL_SIZE, stencilSize,
+                EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
+                EGL_NONE
+        };
+    }
+
+    void initCaches() {
+        if (GLES20Canvas.initCaches()) {
+            // Caches were (re)initialized, rebind atlas
+            initAtlas();
+        }
+    }
+
+    void initAtlas() {
+        IBinder binder = ServiceManager.getService("assetatlas");
+        if (binder == null) return;
+
+        IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
+        try {
+            if (atlas.isCompatible(android.os.Process.myPpid())) {
+                GraphicBuffer buffer = atlas.getBuffer();
+                if (buffer != null) {
+                    int[] map = atlas.getMap();
+                    if (map != null) {
+                        GLES20Canvas.initAtlas(buffer, map);
+                    }
+                    // If IAssetAtlas is not the same class as the IBinder
+                    // we are using a remote service and we can safely
+                    // destroy the graphic buffer
+                    if (atlas.getClass() != binder.getClass()) {
+                        buffer.destroy();
+                    }
+                }
+            }
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "Could not acquire atlas", e);
+        }
+    }
+
+    boolean canDraw() {
+        return mGl != null && mCanvas != null && mGlCanvas != null;
+    }
+
+    int onPreDraw(Rect dirty) {
+        return mGlCanvas.onPreDraw(dirty);
+    }
+
+    void onPostDraw() {
+        mGlCanvas.onPostDraw();
+    }
+
+    void drawProfileData(View.AttachInfo attachInfo) {
+        if (mDebugDataProvider != null) {
+            final GraphDataProvider provider = mDebugDataProvider;
+            initProfileDrawData(attachInfo, provider);
+
+            final int height = provider.getVerticalUnitSize();
+            final int margin = provider.getHorizontaUnitMargin();
+            final int width = provider.getHorizontalUnitSize();
+
+            int x = 0;
+            int count = 0;
+            int current = 0;
+
+            final float[] data = provider.getData();
+            final int elementCount = provider.getElementCount();
+            final int graphType = provider.getGraphType();
+
+            int totalCount = provider.getFrameCount() * elementCount;
+            if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
+                totalCount -= elementCount;
+            }
+
+            for (int i = 0; i < totalCount; i += elementCount) {
+                if (data[i] < 0.0f) break;
+
+                int index = count * 4;
+                if (i == provider.getCurrentFrame() * elementCount) current = index;
+
+                x += margin;
+                int x2 = x + width;
+
+                int y2 = mHeight;
+                int y1 = (int) (y2 - data[i] * height);
+
+                switch (graphType) {
+                    case GraphDataProvider.GRAPH_TYPE_BARS: {
+                        for (int j = 0; j < elementCount; j++) {
+                            //noinspection MismatchedReadAndWriteOfArray
+                            final float[] r = mProfileShapes[j];
+                            r[index] = x;
+                            r[index + 1] = y1;
+                            r[index + 2] = x2;
+                            r[index + 3] = y2;
+
+                            y2 = y1;
+                            if (j < elementCount - 1) {
+                                y1 = (int) (y2 - data[i + j + 1] * height);
+                            }
+                        }
+                    } break;
+                    case GraphDataProvider.GRAPH_TYPE_LINES: {
+                        for (int j = 0; j < elementCount; j++) {
+                            //noinspection MismatchedReadAndWriteOfArray
+                            final float[] r = mProfileShapes[j];
+                            r[index] = (x + x2) * 0.5f;
+                            r[index + 1] = index == 0 ? y1 : r[index - 1];
+                            r[index + 2] = r[index] + width;
+                            r[index + 3] = y1;
+
+                            y2 = y1;
+                            if (j < elementCount - 1) {
+                                y1 = (int) (y2 - data[i + j + 1] * height);
+                            }
+                        }
+                    } break;
+                }
+
+
+                x += width;
+                count++;
+            }
+
+            x += margin;
+
+            drawGraph(graphType, count);
+            drawCurrentFrame(graphType, current);
+            drawThreshold(x, height);
+        }
+    }
+
+    private void drawGraph(int graphType, int count) {
+        for (int i = 0; i < mProfileShapes.length; i++) {
+            mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
+            switch (graphType) {
+                case GraphDataProvider.GRAPH_TYPE_BARS:
+                    mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
+                    break;
+                case GraphDataProvider.GRAPH_TYPE_LINES:
+                    mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
+                    break;
+            }
+        }
+    }
+
+    private void drawCurrentFrame(int graphType, int index) {
+        if (index >= 0) {
+            mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
+            switch (graphType) {
+                case GraphDataProvider.GRAPH_TYPE_BARS:
+                    mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
+                            mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
+                            mProfilePaint);
+                    break;
+                case GraphDataProvider.GRAPH_TYPE_LINES:
+                    mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
+                            mProfileShapes[2][index], mHeight, mProfilePaint);
+                    break;
+            }
+        }
+    }
+
+    private void drawThreshold(int x, int height) {
+        float threshold = mDebugDataProvider.getThreshold();
+        if (threshold > 0.0f) {
+            mDebugDataProvider.setupThresholdPaint(mProfilePaint);
+            int y = (int) (mHeight - threshold * height);
+            mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
+        }
+    }
+
+    private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
+        if (mProfileShapes == null) {
+            final int elementCount = provider.getElementCount();
+            final int frameCount = provider.getFrameCount();
+
+            mProfileShapes = new float[elementCount][];
+            for (int i = 0; i < elementCount; i++) {
+                mProfileShapes[i] = new float[frameCount * 4];
+            }
+
+            mProfilePaint = new Paint();
+        }
+
+        mProfilePaint.reset();
+        if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
+            mProfilePaint.setAntiAlias(true);
+        }
+
+        if (mDisplayMetrics == null) {
+            mDisplayMetrics = new DisplayMetrics();
+        }
+
+        attachInfo.mDisplay.getMetrics(mDisplayMetrics);
+        provider.prepare(mDisplayMetrics);
+    }
+
+    @Override
+    void destroy(boolean full) {
+        try {
+            if (full && mCanvas != null) {
+                mCanvas = null;
+            }
+
+            if (!isEnabled() || mDestroyed) {
+                setEnabled(false);
+                return;
+            }
+
+            destroySurface();
+            setEnabled(false);
+
+            mDestroyed = true;
+            mGl = null;
+        } finally {
+            if (full && mGlCanvas != null) {
+                mGlCanvas = null;
+            }
+        }
+    }
+
+    @Override
+    void pushLayerUpdate(HardwareLayer layer) {
+        mGlCanvas.pushLayerUpdate(layer);
+    }
+
+    @Override
+    void cancelLayerUpdate(HardwareLayer layer) {
+        mGlCanvas.cancelLayerUpdate(layer);
+    }
+
+    @Override
+    void flushLayerUpdates() {
+        mGlCanvas.flushLayerUpdates();
+    }
+
+    @Override
+    HardwareLayer createHardwareLayer(boolean isOpaque) {
+        return new GLES20TextureLayer(isOpaque);
+    }
+
+    @Override
+    public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
+        return new GLES20RenderLayer(width, height, isOpaque);
+    }
+
+    void countOverdraw(HardwareCanvas canvas) {
+        ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
+    }
+
+    float getOverdraw(HardwareCanvas canvas) {
+        return ((GLES20Canvas) canvas).getOverdraw();
+    }
+
+    @Override
+    public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
+        return ((GLES20TextureLayer) layer).getSurfaceTexture();
+    }
+
+    @Override
+    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
+        ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
+    }
+
+    @Override
+    boolean safelyRun(Runnable action) {
+        boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
+
+        if (needsContext) {
+            GLRendererEglContext managedContext =
+                    (GLRendererEglContext) sEglContextStorage.get();
+            if (managedContext == null) return false;
+            usePbufferSurface(managedContext.getContext());
+        }
+
+        try {
+            action.run();
+        } finally {
+            if (needsContext) {
+                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
+                        EGL_NO_SURFACE, EGL_NO_CONTEXT);
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    void destroyLayers(final View view) {
+        if (view != null) {
+            safelyRun(new Runnable() {
+                @Override
+                public void run() {
+                    if (mCanvas != null) {
+                        mCanvas.clearLayerUpdates();
+                    }
+                    destroyHardwareLayer(view);
+                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+                }
+            });
+        }
+    }
+
+    private static void destroyHardwareLayer(View view) {
+        view.destroyLayer(true);
+
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+
+            int count = group.getChildCount();
+            for (int i = 0; i < count; i++) {
+                destroyHardwareLayer(group.getChildAt(i));
+            }
+        }
+    }
+
+    @Override
+    void destroyHardwareResources(final View view) {
+        if (view != null) {
+            safelyRun(new Runnable() {
+                @Override
+                public void run() {
+                    if (mCanvas != null) {
+                        mCanvas.clearLayerUpdates();
+                    }
+                    destroyResources(view);
+                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+                }
+            });
+        }
+    }
+
+    private static void destroyResources(View view) {
+        view.destroyHardwareResources();
+
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+
+            int count = group.getChildCount();
+            for (int i = 0; i < count; i++) {
+                destroyResources(group.getChildAt(i));
+            }
+        }
+    }
+
+    static void startTrimMemory(int level) {
+        if (sEgl == null || sEglConfig == null) return;
+
+        GLRendererEglContext managedContext =
+                (GLRendererEglContext) sEglContextStorage.get();
+        // We do not have OpenGL objects
+        if (managedContext == null) {
+            return;
+        } else {
+            usePbufferSurface(managedContext.getContext());
+        }
+
+        if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+            GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
+        } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
+            GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
+        }
+    }
+
+    static void endTrimMemory() {
+        if (sEgl != null && sEglDisplay != null) {
+            sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+        }
+    }
+
+    private static void usePbufferSurface(EGLContext eglContext) {
+        synchronized (sPbufferLock) {
+            // Create a temporary 1x1 pbuffer so we have a context
+            // to clear our OpenGL objects
+            if (sPbuffer == null) {
+                sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
+                        EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
+                });
+            }
+        }
+        sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+    }
+
+    GLRenderer(boolean translucent) {
+        mTranslucent = translucent;
+
+        loadSystemProperties(null);
+    }
+
+    @Override
+    boolean loadSystemProperties(Surface surface) {
+        boolean value;
+        boolean changed = false;
+
+        String profiling = SystemProperties.get(PROFILE_PROPERTY);
+        int graphType = search(VISUALIZERS, profiling);
+        value = graphType >= 0;
+
+        if (graphType != mProfileVisualizerType) {
+            changed = true;
+            mProfileVisualizerType = graphType;
+
+            mProfileShapes = null;
+            mProfilePaint = null;
+
+            if (value) {
+                mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
+            } else {
+                mDebugDataProvider = null;
+            }
+        }
+
+        // If on-screen profiling is not enabled, we need to check whether
+        // console profiling only is enabled
+        if (!value) {
+            value = Boolean.parseBoolean(profiling);
+        }
+
+        if (value != mProfileEnabled) {
+            changed = true;
+            mProfileEnabled = value;
+
+            if (mProfileEnabled) {
+                Log.d(LOG_TAG, "Profiling hardware renderer");
+
+                int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
+                        PROFILE_MAX_FRAMES);
+                mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
+                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
+                }
+
+                mProfileLock = new ReentrantLock();
+            } else {
+                mProfileData = null;
+                mProfileLock = null;
+                mProfileVisualizerType = -1;
+            }
+
+            mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+        }
+
+        value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
+        if (value != mDebugDirtyRegions) {
+            changed = true;
+            mDebugDirtyRegions = value;
+
+            if (mDebugDirtyRegions) {
+                Log.d(LOG_TAG, "Debugging dirty regions");
+            }
+        }
+
+        String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
+        int debugOverdraw = search(OVERDRAW, overdraw);
+        if (debugOverdraw != mDebugOverdraw) {
+            changed = true;
+            mDebugOverdraw = debugOverdraw;
+
+            if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
+                if (mDebugOverdrawLayer != null) {
+                    mDebugOverdrawLayer.destroy();
+                    mDebugOverdrawLayer = null;
+                    mDebugOverdrawPaint = null;
+                }
+            }
+        }
+
+        if (loadProperties()) {
+            changed = true;
+        }
+
+        return changed;
+    }
+
+    private static int search(String[] values, String value) {
+        for (int i = 0; i < values.length; i++) {
+            if (values[i].equals(value)) return i;
+        }
+        return -1;
+    }
+
+    @Override
+    void dumpGfxInfo(PrintWriter pw) {
+        if (mProfileEnabled) {
+            pw.printf("\n\tDraw\tProcess\tExecute\n");
+
+            mProfileLock.lock();
+            try {
+                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+                    if (mProfileData[i] < 0) {
+                        break;
+                    }
+                    pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
+                            mProfileData[i + 2]);
+                    mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
+                }
+                mProfileCurrentFrame = mProfileData.length;
+            } finally {
+                mProfileLock.unlock();
+            }
+        }
+    }
+
+    @Override
+    long getFrameCount() {
+        return mFrameCount;
+    }
+
+    /**
+     * Indicates whether this renderer instance can track and update dirty regions.
+     */
+    boolean hasDirtyRegions() {
+        return mDirtyRegionsEnabled;
+    }
+
+    /**
+     * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
+     * is invoked and the requested flag is turned off. The error code is
+     * also logged as a warning.
+     */
+    void checkEglErrors() {
+        if (isEnabled()) {
+            checkEglErrorsForced();
+        }
+    }
+
+    private void checkEglErrorsForced() {
+        int error = sEgl.eglGetError();
+        if (error != EGL_SUCCESS) {
+            // something bad has happened revert to
+            // normal rendering.
+            Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
+            fallback(error != EGL11.EGL_CONTEXT_LOST);
+        }
+    }
+
+    private void fallback(boolean fallback) {
+        destroy(true);
+        if (fallback) {
+            // we'll try again if it was context lost
+            setRequested(false);
+            Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
+                    + "Switching back to software rendering.");
+        }
+    }
+
+    @Override
+    boolean initialize(Surface surface) throws OutOfResourcesException {
+        if (isRequested() && !isEnabled()) {
+            boolean contextCreated = initializeEgl();
+            mGl = createEglSurface(surface);
+            mDestroyed = false;
+
+            if (mGl != null) {
+                int err = sEgl.eglGetError();
+                if (err != EGL_SUCCESS) {
+                    destroy(true);
+                    setRequested(false);
+                } else {
+                    if (mCanvas == null) {
+                        mCanvas = createCanvas();
+                        mCanvas.setName(mName);
+                    }
+                    setEnabled(true);
+
+                    if (contextCreated) {
+                        initAtlas();
+                    }
+                }
+
+                return mCanvas != null;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    void updateSurface(Surface surface) throws OutOfResourcesException {
+        if (isRequested() && isEnabled()) {
+            createEglSurface(surface);
+        }
+    }
+
+    boolean initializeEgl() {
+        synchronized (sEglLock) {
+            if (sEgl == null && sEglConfig == null) {
+                sEgl = (EGL10) EGLContext.getEGL();
+
+                // Get to the default display.
+                sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+                if (sEglDisplay == EGL_NO_DISPLAY) {
+                    throw new RuntimeException("eglGetDisplay failed "
+                            + GLUtils.getEGLErrorString(sEgl.eglGetError()));
+                }
+
+                // We can now initialize EGL for that display
+                int[] version = new int[2];
+                if (!sEgl.eglInitialize(sEglDisplay, version)) {
+                    throw new RuntimeException("eglInitialize failed " +
+                            GLUtils.getEGLErrorString(sEgl.eglGetError()));
+                }
+
+                checkEglErrorsForced();
+
+                sEglConfig = loadEglConfig();
+            }
+        }
+
+        ManagedEGLContext managedContext = sEglContextStorage.get();
+        mEglContext = managedContext != null ? managedContext.getContext() : null;
+        mEglThread = Thread.currentThread();
+
+        if (mEglContext == null) {
+            mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
+            sEglContextStorage.set(createManagedContext(mEglContext));
+            return true;
+        }
+
+        return false;
+    }
+
+    private EGLConfig loadEglConfig() {
+        EGLConfig eglConfig = chooseEglConfig();
+        if (eglConfig == null) {
+            // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
+            if (sDirtyRegions) {
+                sDirtyRegions = false;
+                eglConfig = chooseEglConfig();
+                if (eglConfig == null) {
+                    throw new RuntimeException("eglConfig not initialized");
+                }
+            } else {
+                throw new RuntimeException("eglConfig not initialized");
+            }
+        }
+        return eglConfig;
+    }
+
+    private EGLConfig chooseEglConfig() {
+        EGLConfig[] configs = new EGLConfig[1];
+        int[] configsCount = new int[1];
+        int[] configSpec = getConfig(sDirtyRegions);
+
+        // Debug
+        final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
+        if ("all".equalsIgnoreCase(debug)) {
+            sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
+
+            EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
+            sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
+                    configsCount[0], configsCount);
+
+            for (EGLConfig config : debugConfigs) {
+                printConfig(config);
+            }
+        }
+
+        if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
+            throw new IllegalArgumentException("eglChooseConfig failed " +
+                    GLUtils.getEGLErrorString(sEgl.eglGetError()));
+        } else if (configsCount[0] > 0) {
+            if ("choice".equalsIgnoreCase(debug)) {
+                printConfig(configs[0]);
+            }
+            return configs[0];
+        }
+
+        return null;
+    }
+
+    private static void printConfig(EGLConfig config) {
+        int[] value = new int[1];
+
+        Log.d(LOG_TAG, "EGL configuration " + config + ":");
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
+        Log.d(LOG_TAG, "  RED_SIZE = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
+        Log.d(LOG_TAG, "  GREEN_SIZE = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
+        Log.d(LOG_TAG, "  BLUE_SIZE = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
+        Log.d(LOG_TAG, "  ALPHA_SIZE = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
+        Log.d(LOG_TAG, "  DEPTH_SIZE = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
+        Log.d(LOG_TAG, "  STENCIL_SIZE = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
+        Log.d(LOG_TAG, "  SAMPLE_BUFFERS = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
+        Log.d(LOG_TAG, "  SAMPLES = " + value[0]);
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
+        Log.d(LOG_TAG, "  SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
+
+        sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
+        Log.d(LOG_TAG, "  CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
+    }
+
+    GL createEglSurface(Surface surface) throws OutOfResourcesException {
+        // Check preconditions.
+        if (sEgl == null) {
+            throw new RuntimeException("egl not initialized");
+        }
+        if (sEglDisplay == null) {
+            throw new RuntimeException("eglDisplay not initialized");
+        }
+        if (sEglConfig == null) {
+            throw new RuntimeException("eglConfig not initialized");
+        }
+        if (Thread.currentThread() != mEglThread) {
+            throw new IllegalStateException("HardwareRenderer cannot be used "
+                    + "from multiple threads");
+        }
+
+        // In case we need to destroy an existing surface
+        destroySurface();
+
+        // Create an EGL surface we can render into.
+        if (!createSurface(surface)) {
+            return null;
+        }
+
+        initCaches();
+
+        return mEglContext.getGL();
+    }
+
+    private void enableDirtyRegions() {
+        // If mDirtyRegions is set, this means we have an EGL configuration
+        // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
+        if (sDirtyRegions) {
+            if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
+                Log.w(LOG_TAG, "Backbuffer cannot be preserved");
+            }
+        } else if (sDirtyRegionsRequested) {
+            // If mDirtyRegions is not set, our EGL configuration does not
+            // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
+            // swap behavior might be EGL_BUFFER_PRESERVED, which means we
+            // want to set mDirtyRegions. We try to do this only if dirty
+            // regions were initially requested as part of the device
+            // configuration (see RENDER_DIRTY_REGIONS)
+            mDirtyRegionsEnabled = isBackBufferPreserved();
+        }
+    }
+
+    EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+        final int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, GL_VERSION, EGL_NONE };
+
+        EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
+                attribs);
+        if (context == null || context == EGL_NO_CONTEXT) {
+            //noinspection ConstantConditions
+            throw new IllegalStateException(
+                    "Could not create an EGL context. eglCreateContext failed with error: " +
+                    GLUtils.getEGLErrorString(sEgl.eglGetError()));
+        }
+
+        return context;
+    }
+
+    void destroySurface() {
+        if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+            if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
+                sEgl.eglMakeCurrent(sEglDisplay,
+                        EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+            }
+            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+            mEglSurface = null;
+        }
+    }
+
+    @Override
+    void invalidate(Surface surface) {
+        // Cancels any existing buffer to ensure we'll get a buffer
+        // of the right size before we call eglSwapBuffers
+        sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+        if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+            mEglSurface = null;
+            setEnabled(false);
+        }
+
+        if (surface.isValid()) {
+            if (!createSurface(surface)) {
+                return;
+            }
+
+            mUpdateDirtyRegions = true;
+
+            if (mCanvas != null) {
+                setEnabled(true);
+            }
+        }
+    }
+
+    private boolean createSurface(Surface surface) {
+        mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
+
+        if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
+            int error = sEgl.eglGetError();
+            if (error == EGL_BAD_NATIVE_WINDOW) {
+                Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                return false;
+            }
+            throw new RuntimeException("createWindowSurface failed "
+                    + GLUtils.getEGLErrorString(error));
+        }
+
+        if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+            throw new IllegalStateException("eglMakeCurrent failed " +
+                    GLUtils.getEGLErrorString(sEgl.eglGetError()));
+        }
+
+        enableDirtyRegions();
+
+        return true;
+    }
+
+    @Override
+    boolean validate() {
+        return checkRenderContext() != SURFACE_STATE_ERROR;
+    }
+
+    @Override
+    void setup(int width, int height) {
+        if (validate()) {
+            mCanvas.setViewport(width, height);
+            mWidth = width;
+            mHeight = height;
+        }
+    }
+
+    @Override
+    int getWidth() {
+        return mWidth;
+    }
+
+    @Override
+    int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    HardwareCanvas getCanvas() {
+        return mCanvas;
+    }
+
+    @Override
+    void setName(String name) {
+        mName = name;
+    }
+
+    class FunctorsRunnable implements Runnable {
+        View.AttachInfo attachInfo;
+
+        @Override
+        public void run() {
+            final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
+            if (renderer == null || !renderer.isEnabled() || renderer != GLRenderer.this) {
+                return;
+            }
+
+            if (checkRenderContext() != SURFACE_STATE_ERROR) {
+                int status = mCanvas.invokeFunctors(mRedrawClip);
+                handleFunctorStatus(attachInfo, status);
+            }
+        }
+    }
+
+    @Override
+    void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
+            Rect dirty) {
+        if (canDraw()) {
+            if (!hasDirtyRegions()) {
+                dirty = null;
+            }
+            attachInfo.mIgnoreDirtyState = true;
+            attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+
+            view.mPrivateFlags |= View.PFLAG_DRAWN;
+
+            // We are already on the correct thread
+            final int surfaceState = checkRenderContextUnsafe();
+            if (surfaceState != SURFACE_STATE_ERROR) {
+                HardwareCanvas canvas = mCanvas;
+                attachInfo.mHardwareCanvas = canvas;
+
+                if (mProfileEnabled) {
+                    mProfileLock.lock();
+                }
+
+                dirty = beginFrame(canvas, dirty, surfaceState);
+
+                DisplayList displayList = buildDisplayList(view, canvas);
+
+                // buildDisplayList() calls into user code which can cause
+                // an eglMakeCurrent to happen with a different surface/context.
+                // We must therefore check again here.
+                if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
+                    return;
+                }
+
+                int saveCount = 0;
+                int status = DisplayList.STATUS_DONE;
+
+                long start = getSystemTime();
+                try {
+                    status = prepareFrame(dirty);
+
+                    saveCount = canvas.save();
+                    callbacks.onHardwarePreDraw(canvas);
+
+                    if (displayList != null) {
+                        status |= drawDisplayList(attachInfo, canvas, displayList, status);
+                    } else {
+                        // Shouldn't reach here
+                        view.draw(canvas);
+                    }
+                } catch (Exception e) {
+                    Log.e(LOG_TAG, "An error has occurred while drawing:", e);
+                } finally {
+                    callbacks.onHardwarePostDraw(canvas);
+                    canvas.restoreToCount(saveCount);
+                    view.mRecreateDisplayList = false;
+
+                    mDrawDelta = getSystemTime() - start;
+
+                    if (mDrawDelta > 0) {
+                        mFrameCount++;
+
+                        debugOverdraw(attachInfo, dirty, canvas, displayList);
+                        debugDirtyRegions(dirty, canvas);
+                        drawProfileData(attachInfo);
+                    }
+                }
+
+                onPostDraw();
+
+                swapBuffers(status);
+
+                if (mProfileEnabled) {
+                    mProfileLock.unlock();
+                }
+
+                attachInfo.mIgnoreDirtyState = false;
+            }
+        }
+    }
+
+    private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
+            HardwareCanvas canvas, DisplayList displayList) {
+
+        if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
+            if (mDebugOverdrawLayer == null) {
+                mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
+            } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
+                    mDebugOverdrawLayer.getHeight() != mHeight) {
+                mDebugOverdrawLayer.resize(mWidth, mHeight);
+            }
+
+            if (!mDebugOverdrawLayer.isValid()) {
+                mDebugOverdraw = -1;
+                return;
+            }
+
+            HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
+            countOverdraw(layerCanvas);
+            final int restoreCount = layerCanvas.save();
+            layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
+            layerCanvas.restoreToCount(restoreCount);
+            mDebugOverdrawLayer.end(canvas);
+
+            float overdraw = getOverdraw(layerCanvas);
+            DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
+
+            drawOverdrawCounter(canvas, overdraw, metrics.density);
+        }
+    }
+
+    private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
+        final String text = String.format("%.2fx", overdraw);
+        final Paint paint = setupPaint(density);
+        // HSBtoColor will clamp the values in the 0..1 range
+        paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
+
+        canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
+    }
+
+    private Paint setupPaint(float density) {
+        if (mDebugOverdrawPaint == null) {
+            mDebugOverdrawPaint = new Paint();
+            mDebugOverdrawPaint.setAntiAlias(true);
+            mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
+            mDebugOverdrawPaint.setTextSize(density * 20.0f);
+        }
+        return mDebugOverdrawPaint;
+    }
+
+    private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
+        if (mDrawDelta <= 0) {
+            return view.mDisplayList;
+        }
+
+        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
+                == View.PFLAG_INVALIDATED;
+        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
+
+        long buildDisplayListStartTime = startBuildDisplayListProfiling();
+        canvas.clearLayerUpdates();
+
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+        DisplayList displayList = view.getDisplayList();
+        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+
+        endBuildDisplayListProfiling(buildDisplayListStartTime);
+
+        return displayList;
+    }
+
+    private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
+        // We had to change the current surface and/or context, redraw everything
+        if (surfaceState == SURFACE_STATE_UPDATED) {
+            dirty = null;
+            beginFrame(null);
+        } else {
+            int[] size = mSurfaceSize;
+            beginFrame(size);
+
+            if (size[1] != mHeight || size[0] != mWidth) {
+                mWidth = size[0];
+                mHeight = size[1];
+
+                canvas.setViewport(mWidth, mHeight);
+
+                dirty = null;
+            }
+        }
+
+        if (mDebugDataProvider != null) dirty = null;
+
+        return dirty;
+    }
+
+    private long startBuildDisplayListProfiling() {
+        if (mProfileEnabled) {
+            mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
+            if (mProfileCurrentFrame >= mProfileData.length) {
+                mProfileCurrentFrame = 0;
+            }
+
+            return System.nanoTime();
+        }
+        return 0;
+    }
+
+    private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
+        if (mProfileEnabled) {
+            long now = System.nanoTime();
+            float total = (now - getDisplayListStartTime) * 0.000001f;
+            //noinspection PointlessArithmeticExpression
+            mProfileData[mProfileCurrentFrame] = total;
+        }
+    }
+
+    private int prepareFrame(Rect dirty) {
+        int status;
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
+        try {
+            status = onPreDraw(dirty);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+        return status;
+    }
+
+    private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
+            DisplayList displayList, int status) {
+
+        long drawDisplayListStartTime = 0;
+        if (mProfileEnabled) {
+            drawDisplayListStartTime = System.nanoTime();
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
+        try {
+            status |= canvas.drawDisplayList(displayList, mRedrawClip,
+                    DisplayList.FLAG_CLIP_CHILDREN);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+        }
+
+        if (mProfileEnabled) {
+            long now = System.nanoTime();
+            float total = (now - drawDisplayListStartTime) * 0.000001f;
+            mProfileData[mProfileCurrentFrame + 1] = total;
+        }
+
+        handleFunctorStatus(attachInfo, status);
+        return status;
+    }
+
+    private void swapBuffers(int status) {
+        if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
+            long eglSwapBuffersStartTime = 0;
+            if (mProfileEnabled) {
+                eglSwapBuffersStartTime = System.nanoTime();
+            }
+
+            sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
+
+            if (mProfileEnabled) {
+                long now = System.nanoTime();
+                float total = (now - eglSwapBuffersStartTime) * 0.000001f;
+                mProfileData[mProfileCurrentFrame + 2] = total;
+            }
+
+            checkEglErrors();
+        }
+    }
+
+    private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
+        if (mDebugDirtyRegions) {
+            if (mDebugPaint == null) {
+                mDebugPaint = new Paint();
+                mDebugPaint.setColor(0x7fff0000);
+            }
+
+            if (dirty != null && (mFrameCount & 1) == 0) {
+                canvas.drawRect(dirty, mDebugPaint);
+            }
+        }
+    }
+
+    private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
+        // If the draw flag is set, functors will be invoked while executing
+        // the tree of display lists
+        if ((status & DisplayList.STATUS_DRAW) != 0) {
+            if (mRedrawClip.isEmpty()) {
+                attachInfo.mViewRootImpl.invalidate();
+            } else {
+                attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
+                mRedrawClip.setEmpty();
+            }
+        }
+
+        if ((status & DisplayList.STATUS_INVOKE) != 0 ||
+                attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
+            attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
+            mFunctorsRunnable.attachInfo = attachInfo;
+            attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
+        }
+    }
+
+    @Override
+    void detachFunctor(int functor) {
+        if (mCanvas != null) {
+            mCanvas.detachFunctor(functor);
+        }
+    }
+
+    @Override
+    boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
+        if (mCanvas != null) {
+            mCanvas.attachFunctor(functor);
+            mFunctorsRunnable.attachInfo = attachInfo;
+            attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
+            attachInfo.mHandler.postDelayed(mFunctorsRunnable,  0);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Ensures the current EGL context and surface are the ones we expect.
+     * This method throws an IllegalStateException if invoked from a thread
+     * that did not initialize EGL.
+     *
+     * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
+     *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
+     *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
+     *
+     * @see #checkRenderContextUnsafe()
+     */
+    int checkRenderContext() {
+        if (mEglThread != Thread.currentThread()) {
+            throw new IllegalStateException("Hardware acceleration can only be used with a " +
+                    "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
+                    "Current thread: " + Thread.currentThread());
+        }
+
+        return checkRenderContextUnsafe();
+    }
+
+    /**
+     * Ensures the current EGL context and surface are the ones we expect.
+     * This method does not check the current thread.
+     *
+     * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
+     *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
+     *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
+     *
+     * @see #checkRenderContext()
+     */
+    private int checkRenderContextUnsafe() {
+        if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
+                !mEglContext.equals(sEgl.eglGetCurrentContext())) {
+            if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                Log.e(LOG_TAG, "eglMakeCurrent failed " +
+                        GLUtils.getEGLErrorString(sEgl.eglGetError()));
+                fallback(true);
+                return SURFACE_STATE_ERROR;
+            } else {
+                if (mUpdateDirtyRegions) {
+                    enableDirtyRegions();
+                    mUpdateDirtyRegions = false;
+                }
+                return SURFACE_STATE_UPDATED;
+            }
+        }
+        return SURFACE_STATE_SUCCESS;
+    }
+
+    private static int dpToPx(int dp, float density) {
+        return (int) (dp * density + 0.5f);
+    }
+
+    private static native boolean loadProperties();
+
+    static native void setupShadersDiskCache(String cacheFile);
+
+    /**
+     * Notifies EGL that the frame is about to be rendered.
+     * @param size
+     */
+    private static native void beginFrame(int[] size);
+
+    /**
+     * Returns the current system time according to the renderer.
+     * This method is used for debugging only and should not be used
+     * as a clock.
+     */
+    private static native long getSystemTime();
+
+    /**
+     * Preserves the back buffer of the current surface after a buffer swap.
+     * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
+     * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
+     * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
+     *
+     * @return True if the swap behavior was successfully changed,
+     *         false otherwise.
+     */
+    private static native boolean preserveBackBuffer();
+
+    /**
+     * Indicates whether the current surface preserves its back buffer
+     * after a buffer swap.
+     *
+     * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
+     *         false otherwise
+     */
+    private static native boolean isBackBufferPreserved();
+
+    class DrawPerformanceDataProvider extends GraphDataProvider {
+        private final int mGraphType;
+
+        private int mVerticalUnit;
+        private int mHorizontalUnit;
+        private int mHorizontalMargin;
+        private int mThresholdStroke;
+
+        DrawPerformanceDataProvider(int graphType) {
+            mGraphType = graphType;
+        }
+
+        @Override
+        void prepare(DisplayMetrics metrics) {
+            final float density = metrics.density;
+
+            mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
+            mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
+            mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
+            mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
+        }
+
+        @Override
+        int getGraphType() {
+            return mGraphType;
+        }
+
+        @Override
+        int getVerticalUnitSize() {
+            return mVerticalUnit;
+        }
+
+        @Override
+        int getHorizontalUnitSize() {
+            return mHorizontalUnit;
+        }
+
+        @Override
+        int getHorizontaUnitMargin() {
+            return mHorizontalMargin;
+        }
+
+        @Override
+        float[] getData() {
+            return mProfileData;
+        }
+
+        @Override
+        float getThreshold() {
+            return 16;
+        }
+
+        @Override
+        int getFrameCount() {
+            return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
+        }
+
+        @Override
+        int getElementCount() {
+            return PROFILE_FRAME_DATA_COUNT;
+        }
+
+        @Override
+        int getCurrentFrame() {
+            return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
+        }
+
+        @Override
+        void setupGraphPaint(Paint paint, int elementIndex) {
+            paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
+            if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
+        }
+
+        @Override
+        void setupThresholdPaint(Paint paint) {
+            paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
+            paint.setStrokeWidth(mThresholdStroke);
+        }
+
+        @Override
+        void setupCurrentFramePaint(Paint paint) {
+            paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
+            if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
+        }
+    }
+}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f215189..5c0be4a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -16,41 +16,14 @@
 
 package android.view;
 
-import android.content.ComponentCallbacks2;
-import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
-import android.opengl.EGL14;
-import android.opengl.GLUtils;
-import android.opengl.ManagedEGLContext;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.Trace;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.view.Surface.OutOfResourcesException;
 
-import com.google.android.gles_jni.EGLImpl;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGL11;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL;
-
 import java.io.File;
 import java.io.PrintWriter;
-import java.util.concurrent.locks.ReentrantLock;
-
-import static javax.microedition.khronos.egl.EGL10.*;
 
 /**
  * Interface for rendering a view hierarchy using hardware acceleration.
@@ -66,13 +39,6 @@
     private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
 
     /**
-     * Turn on to only refresh the parts of the screen that need updating.
-     * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
-     * must also have the value "true".
-     */
-    static final boolean RENDER_DIRTY_REGIONS = true;
-
-    /**
      * System property used to enable or disable dirty regions invalidation.
      * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
      * The default value of this property is assumed to be true.
@@ -222,16 +188,6 @@
      */
     public static boolean sSystemRendererDisabled = false;
 
-    /**
-     * Number of frames to profile.
-     */
-    private static final int PROFILE_MAX_FRAMES = 128;
-
-    /**
-     * Number of floats per profiled frame.
-     */
-    private static final int PROFILE_FRAME_DATA_COUNT = 3;
-
     private boolean mEnabled;
     private boolean mRequested = true;
 
@@ -381,8 +337,6 @@
      */
     abstract boolean loadSystemProperties(Surface surface);
 
-    private static native boolean nLoadProperties();
-
     /**
      * Sets the directory to use as a persistent storage for hardware rendering
      * resources.
@@ -392,60 +346,9 @@
      * @hide
      */
     public static void setupDiskCache(File cacheDir) {
-        nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
+        GLRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
     }
 
-    private static native void nSetupShadersDiskCache(String cacheFile);
-
-    /**
-     * Notifies EGL that the frame is about to be rendered.
-     * @param size
-     */
-    static void beginFrame(int[] size) {
-        nBeginFrame(size);
-    }
-
-    private static native void nBeginFrame(int[] size);
-
-    /**
-     * Returns the current system time according to the renderer.
-     * This method is used for debugging only and should not be used
-     * as a clock.
-     */
-    static long getSystemTime() {
-        return nGetSystemTime();
-    }
-
-    private static native long nGetSystemTime();
-
-    /**
-     * Preserves the back buffer of the current surface after a buffer swap.
-     * Calling this method sets the EGL_SWAP_BEHAVIOR attribute of the current
-     * surface to EGL_BUFFER_PRESERVED. Calling this method requires an EGL
-     * config that supports EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
-     *
-     * @return True if the swap behavior was successfully changed,
-     *         false otherwise.
-     */
-    static boolean preserveBackBuffer() {
-        return nPreserveBackBuffer();
-    }
-
-    private static native boolean nPreserveBackBuffer();
-
-    /**
-     * Indicates whether the current surface preserves its back buffer
-     * after a buffer swap.
-     *
-     * @return True, if the surface's EGL_SWAP_BEHAVIOR is EGL_BUFFER_PRESERVED,
-     *         false otherwise
-     */
-    static boolean isBackBufferPreserved() {
-        return nIsBackBufferPreserved();
-    }
-
-    private static native boolean nIsBackBufferPreserved();
-
     /**
      * Indicates that the specified hardware layer needs to be updated
      * as soon as possible.
@@ -509,18 +412,6 @@
             Rect dirty);
 
     /**
-     * Creates a new display list that can be used to record batches of
-     * drawing operations.
-     *
-     * @param name The name of the display list, used for debugging purpose. May be null.
-     *
-     * @return A new display list.
-     *
-     * @hide
-     */
-    public abstract DisplayList createDisplayList(String name);
-
-    /**
      * Creates a new hardware layer. A hardware layer built by calling this
      * method will be treated as a texture layer, instead of as a render target.
      *
@@ -621,17 +512,15 @@
     /**
      * Creates a hardware renderer using OpenGL.
      *
-     * @param glVersion The version of OpenGL to use (1 for OpenGL 1, 11 for OpenGL 1.1, etc.)
      * @param translucent True if the surface is translucent, false otherwise
      *
      * @return A hardware renderer backed by OpenGL.
      */
-    static HardwareRenderer createGlRenderer(int glVersion, boolean translucent) {
-        switch (glVersion) {
-            case 2:
-                return Gl20Renderer.create(translucent);
+    static HardwareRenderer create(boolean translucent) {
+        if (GLES20Canvas.isAvailable()) {
+            return new GLRenderer(translucent);
         }
-        throw new IllegalArgumentException("Unknown GL version: " + glVersion);
+        return null;
     }
 
     /**
@@ -656,7 +545,7 @@
      *              see {@link android.content.ComponentCallbacks}
      */
     static void startTrimMemory(int level) {
-        Gl20Renderer.startTrimMemory(level);
+        GLRenderer.startTrimMemory(level);
     }
 
     /**
@@ -664,7 +553,7 @@
      * cleanup special resources used by the memory trimming process.
      */
     static void endTrimMemory() {
-        Gl20Renderer.endTrimMemory();
+        GLRenderer.endTrimMemory();
     }
 
     /**
@@ -798,1553 +687,4 @@
          */
         abstract void setupCurrentFramePaint(Paint paint);
     }
-
-    @SuppressWarnings({"deprecation"})
-    static abstract class GlRenderer extends HardwareRenderer {
-        static final int SURFACE_STATE_ERROR = 0;
-        static final int SURFACE_STATE_SUCCESS = 1;
-        static final int SURFACE_STATE_UPDATED = 2;
-
-        static final int FUNCTOR_PROCESS_DELAY = 4;
-
-        private static final int PROFILE_DRAW_MARGIN = 0;
-        private static final int PROFILE_DRAW_WIDTH = 3;
-        private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
-        private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
-        private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
-        private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
-        private static final int PROFILE_DRAW_DP_PER_MS = 7;
-
-        private static final String[] VISUALIZERS = {
-                PROFILE_PROPERTY_VISUALIZE_BARS,
-                PROFILE_PROPERTY_VISUALIZE_LINES
-        };
-
-        private static final String[] OVERDRAW = {
-                OVERDRAW_PROPERTY_SHOW,
-                OVERDRAW_PROPERTY_COUNT
-        };
-        private static final int OVERDRAW_TYPE_COUNT = 1;
-
-        static EGL10 sEgl;
-        static EGLDisplay sEglDisplay;
-        static EGLConfig sEglConfig;
-        static final Object[] sEglLock = new Object[0];
-        int mWidth = -1, mHeight = -1;
-
-        static final ThreadLocal<ManagedEGLContext> sEglContextStorage
-                = new ThreadLocal<ManagedEGLContext>();
-
-        EGLContext mEglContext;
-        Thread mEglThread;
-
-        EGLSurface mEglSurface;
-
-        GL mGl;
-        HardwareCanvas mCanvas;
-
-        String mName;
-
-        long mFrameCount;
-        Paint mDebugPaint;
-
-        static boolean sDirtyRegions;
-        static final boolean sDirtyRegionsRequested;
-        static {
-            String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
-            sDirtyRegionsRequested = sDirtyRegions;
-        }
-
-        boolean mDirtyRegionsEnabled;
-        boolean mUpdateDirtyRegions;
-
-        boolean mProfileEnabled;
-        int mProfileVisualizerType = -1;
-        float[] mProfileData;
-        ReentrantLock mProfileLock;
-        int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-
-        GraphDataProvider mDebugDataProvider;
-        float[][] mProfileShapes;
-        Paint mProfilePaint;
-
-        boolean mDebugDirtyRegions;
-        int mDebugOverdraw = -1;
-        HardwareLayer mDebugOverdrawLayer;
-        Paint mDebugOverdrawPaint;
-
-        final int mGlVersion;
-        final boolean mTranslucent;
-
-        private boolean mDestroyed;
-
-        private final Rect mRedrawClip = new Rect();
-
-        private final int[] mSurfaceSize = new int[2];
-        private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
-
-        private long mDrawDelta = Long.MAX_VALUE;
-
-        GlRenderer(int glVersion, boolean translucent) {
-            mGlVersion = glVersion;
-            mTranslucent = translucent;
-
-            loadSystemProperties(null);
-        }
-
-        @Override
-        boolean loadSystemProperties(Surface surface) {
-            boolean value;
-            boolean changed = false;
-
-            String profiling = SystemProperties.get(PROFILE_PROPERTY);
-            int graphType = search(VISUALIZERS, profiling);
-            value = graphType >= 0;
-
-            if (graphType != mProfileVisualizerType) {
-                changed = true;
-                mProfileVisualizerType = graphType;
-
-                mProfileShapes = null;
-                mProfilePaint = null;
-
-                if (value) {
-                    mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
-                } else {
-                    mDebugDataProvider = null;
-                }
-            }
-
-            // If on-screen profiling is not enabled, we need to check whether
-            // console profiling only is enabled
-            if (!value) {
-                value = Boolean.parseBoolean(profiling);
-            }
-
-            if (value != mProfileEnabled) {
-                changed = true;
-                mProfileEnabled = value;
-
-                if (mProfileEnabled) {
-                    Log.d(LOG_TAG, "Profiling hardware renderer");
-
-                    int maxProfileFrames = SystemProperties.getInt(PROFILE_MAXFRAMES_PROPERTY,
-                            PROFILE_MAX_FRAMES);
-                    mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
-                    for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                        mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
-                    }
-
-                    mProfileLock = new ReentrantLock();
-                } else {
-                    mProfileData = null;
-                    mProfileLock = null;
-                    mProfileVisualizerType = -1;
-                }
-
-                mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
-            }
-
-            value = SystemProperties.getBoolean(DEBUG_DIRTY_REGIONS_PROPERTY, false);
-            if (value != mDebugDirtyRegions) {
-                changed = true;
-                mDebugDirtyRegions = value;
-
-                if (mDebugDirtyRegions) {
-                    Log.d(LOG_TAG, "Debugging dirty regions");
-                }
-            }
-
-            String overdraw = SystemProperties.get(HardwareRenderer.DEBUG_OVERDRAW_PROPERTY);
-            int debugOverdraw = search(OVERDRAW, overdraw);
-            if (debugOverdraw != mDebugOverdraw) {
-                changed = true;
-                mDebugOverdraw = debugOverdraw;
-
-                if (mDebugOverdraw != OVERDRAW_TYPE_COUNT) {
-                    if (mDebugOverdrawLayer != null) {
-                        mDebugOverdrawLayer.destroy();
-                        mDebugOverdrawLayer = null;
-                        mDebugOverdrawPaint = null;
-                    }
-                }
-            }
-
-            if (nLoadProperties()) {
-                changed = true;
-            }
-
-            return changed;
-        }
-
-        private static int search(String[] values, String value) {
-            for (int i = 0; i < values.length; i++) {
-                if (values[i].equals(value)) return i;
-            }
-            return -1;
-        }
-
-        @Override
-        void dumpGfxInfo(PrintWriter pw) {
-            if (mProfileEnabled) {
-                pw.printf("\n\tDraw\tProcess\tExecute\n");
-
-                mProfileLock.lock();
-                try {
-                    for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                        if (mProfileData[i] < 0) {
-                            break;
-                        }
-                        pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
-                                mProfileData[i + 2]);
-                        mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
-                    }
-                    mProfileCurrentFrame = mProfileData.length;
-                } finally {
-                    mProfileLock.unlock();
-                }
-            }
-        }
-
-        @Override
-        long getFrameCount() {
-            return mFrameCount;
-        }
-
-        /**
-         * Indicates whether this renderer instance can track and update dirty regions.
-         */
-        boolean hasDirtyRegions() {
-            return mDirtyRegionsEnabled;
-        }
-
-        /**
-         * Checks for OpenGL errors. If an error has occured, {@link #destroy(boolean)}
-         * is invoked and the requested flag is turned off. The error code is
-         * also logged as a warning.
-         */
-        void checkEglErrors() {
-            if (isEnabled()) {
-                checkEglErrorsForced();
-            }
-        }
-
-        private void checkEglErrorsForced() {
-            int error = sEgl.eglGetError();
-            if (error != EGL_SUCCESS) {
-                // something bad has happened revert to
-                // normal rendering.
-                Log.w(LOG_TAG, "EGL error: " + GLUtils.getEGLErrorString(error));
-                fallback(error != EGL11.EGL_CONTEXT_LOST);
-            }
-        }
-
-        private void fallback(boolean fallback) {
-            destroy(true);
-            if (fallback) {
-                // we'll try again if it was context lost
-                setRequested(false);
-                Log.w(LOG_TAG, "Mountain View, we've had a problem here. "
-                        + "Switching back to software rendering.");
-            }
-        }
-
-        @Override
-        boolean initialize(Surface surface) throws OutOfResourcesException {
-            if (isRequested() && !isEnabled()) {
-                boolean contextCreated = initializeEgl();
-                mGl = createEglSurface(surface);
-                mDestroyed = false;
-
-                if (mGl != null) {
-                    int err = sEgl.eglGetError();
-                    if (err != EGL_SUCCESS) {
-                        destroy(true);
-                        setRequested(false);
-                    } else {
-                        if (mCanvas == null) {
-                            mCanvas = createCanvas();
-                            mCanvas.setName(mName);
-                        }
-                        setEnabled(true);
-
-                        if (contextCreated) {
-                            initAtlas();
-                        }
-                    }
-
-                    return mCanvas != null;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        void updateSurface(Surface surface) throws OutOfResourcesException {
-            if (isRequested() && isEnabled()) {
-                createEglSurface(surface);
-            }
-        }
-
-        abstract HardwareCanvas createCanvas();
-
-        abstract int[] getConfig(boolean dirtyRegions);
-
-        boolean initializeEgl() {
-            synchronized (sEglLock) {
-                if (sEgl == null && sEglConfig == null) {
-                    sEgl = (EGL10) EGLContext.getEGL();
-
-                    // Get to the default display.
-                    sEglDisplay = sEgl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
-
-                    if (sEglDisplay == EGL_NO_DISPLAY) {
-                        throw new RuntimeException("eglGetDisplay failed "
-                                + GLUtils.getEGLErrorString(sEgl.eglGetError()));
-                    }
-
-                    // We can now initialize EGL for that display
-                    int[] version = new int[2];
-                    if (!sEgl.eglInitialize(sEglDisplay, version)) {
-                        throw new RuntimeException("eglInitialize failed " +
-                                GLUtils.getEGLErrorString(sEgl.eglGetError()));
-                    }
-
-                    checkEglErrorsForced();
-
-                    sEglConfig = loadEglConfig();
-                }
-            }
-
-            ManagedEGLContext managedContext = sEglContextStorage.get();
-            mEglContext = managedContext != null ? managedContext.getContext() : null;
-            mEglThread = Thread.currentThread();
-
-            if (mEglContext == null) {
-                mEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
-                sEglContextStorage.set(createManagedContext(mEglContext));
-                return true;
-            }
-
-            return false;
-        }
-
-        private EGLConfig loadEglConfig() {
-            EGLConfig eglConfig = chooseEglConfig();
-            if (eglConfig == null) {
-                // We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
-                if (sDirtyRegions) {
-                    sDirtyRegions = false;
-                    eglConfig = chooseEglConfig();
-                    if (eglConfig == null) {
-                        throw new RuntimeException("eglConfig not initialized");
-                    }
-                } else {
-                    throw new RuntimeException("eglConfig not initialized");
-                }
-            }
-            return eglConfig;
-        }
-
-        abstract ManagedEGLContext createManagedContext(EGLContext eglContext);
-
-        private EGLConfig chooseEglConfig() {
-            EGLConfig[] configs = new EGLConfig[1];
-            int[] configsCount = new int[1];
-            int[] configSpec = getConfig(sDirtyRegions);
-
-            // Debug
-            final String debug = SystemProperties.get(PRINT_CONFIG_PROPERTY, "");
-            if ("all".equalsIgnoreCase(debug)) {
-                sEgl.eglChooseConfig(sEglDisplay, configSpec, null, 0, configsCount);
-
-                EGLConfig[] debugConfigs = new EGLConfig[configsCount[0]];
-                sEgl.eglChooseConfig(sEglDisplay, configSpec, debugConfigs,
-                        configsCount[0], configsCount);
-
-                for (EGLConfig config : debugConfigs) {
-                    printConfig(config);
-                }
-            }
-
-            if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
-                throw new IllegalArgumentException("eglChooseConfig failed " +
-                        GLUtils.getEGLErrorString(sEgl.eglGetError()));
-            } else if (configsCount[0] > 0) {
-                if ("choice".equalsIgnoreCase(debug)) {
-                    printConfig(configs[0]);
-                }
-                return configs[0];
-            }
-
-            return null;
-        }
-
-        private static void printConfig(EGLConfig config) {
-            int[] value = new int[1];
-
-            Log.d(LOG_TAG, "EGL configuration " + config + ":");
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_RED_SIZE, value);
-            Log.d(LOG_TAG, "  RED_SIZE = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_GREEN_SIZE, value);
-            Log.d(LOG_TAG, "  GREEN_SIZE = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_BLUE_SIZE, value);
-            Log.d(LOG_TAG, "  BLUE_SIZE = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_ALPHA_SIZE, value);
-            Log.d(LOG_TAG, "  ALPHA_SIZE = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_DEPTH_SIZE, value);
-            Log.d(LOG_TAG, "  DEPTH_SIZE = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_STENCIL_SIZE, value);
-            Log.d(LOG_TAG, "  STENCIL_SIZE = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLE_BUFFERS, value);
-            Log.d(LOG_TAG, "  SAMPLE_BUFFERS = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SAMPLES, value);
-            Log.d(LOG_TAG, "  SAMPLES = " + value[0]);
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_SURFACE_TYPE, value);
-            Log.d(LOG_TAG, "  SURFACE_TYPE = 0x" + Integer.toHexString(value[0]));
-
-            sEgl.eglGetConfigAttrib(sEglDisplay, config, EGL_CONFIG_CAVEAT, value);
-            Log.d(LOG_TAG, "  CONFIG_CAVEAT = 0x" + Integer.toHexString(value[0]));
-        }
-
-        GL createEglSurface(Surface surface) throws OutOfResourcesException {
-            // Check preconditions.
-            if (sEgl == null) {
-                throw new RuntimeException("egl not initialized");
-            }
-            if (sEglDisplay == null) {
-                throw new RuntimeException("eglDisplay not initialized");
-            }
-            if (sEglConfig == null) {
-                throw new RuntimeException("eglConfig not initialized");
-            }
-            if (Thread.currentThread() != mEglThread) {
-                throw new IllegalStateException("HardwareRenderer cannot be used "
-                        + "from multiple threads");
-            }
-
-            // In case we need to destroy an existing surface
-            destroySurface();
-
-            // Create an EGL surface we can render into.
-            if (!createSurface(surface)) {
-                return null;
-            }
-
-            initCaches();
-
-            return mEglContext.getGL();
-        }
-
-        private void enableDirtyRegions() {
-            // If mDirtyRegions is set, this means we have an EGL configuration
-            // with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
-            if (sDirtyRegions) {
-                if (!(mDirtyRegionsEnabled = preserveBackBuffer())) {
-                    Log.w(LOG_TAG, "Backbuffer cannot be preserved");
-                }
-            } else if (sDirtyRegionsRequested) {
-                // If mDirtyRegions is not set, our EGL configuration does not
-                // have EGL_SWAP_BEHAVIOR_PRESERVED_BIT; however, the default
-                // swap behavior might be EGL_BUFFER_PRESERVED, which means we
-                // want to set mDirtyRegions. We try to do this only if dirty
-                // regions were initially requested as part of the device
-                // configuration (see RENDER_DIRTY_REGIONS)
-                mDirtyRegionsEnabled = isBackBufferPreserved();
-            }
-        }
-
-        abstract void initCaches();
-        abstract void initAtlas();
-
-        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
-            int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
-
-            EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
-                    mGlVersion != 0 ? attribs : null);
-            if (context == null || context == EGL_NO_CONTEXT) {
-                //noinspection ConstantConditions
-                throw new IllegalStateException(
-                        "Could not create an EGL context. eglCreateContext failed with error: " +
-                        GLUtils.getEGLErrorString(sEgl.eglGetError()));
-            }
-
-            return context;
-        }
-
-        @Override
-        void destroy(boolean full) {
-            if (full && mCanvas != null) {
-                mCanvas = null;
-            }
-
-            if (!isEnabled() || mDestroyed) {
-                setEnabled(false);
-                return;
-            }
-
-            destroySurface();
-            setEnabled(false);
-
-            mDestroyed = true;
-            mGl = null;
-        }
-
-        void destroySurface() {
-            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
-                if (mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW))) {
-                    sEgl.eglMakeCurrent(sEglDisplay,
-                            EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-                }
-                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
-                mEglSurface = null;
-            }
-        }
-
-        @Override
-        void invalidate(Surface surface) {
-            // Cancels any existing buffer to ensure we'll get a buffer
-            // of the right size before we call eglSwapBuffers
-            sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
-                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
-                mEglSurface = null;
-                setEnabled(false);
-            }
-
-            if (surface.isValid()) {
-                if (!createSurface(surface)) {
-                    return;
-                }
-
-                mUpdateDirtyRegions = true;
-
-                if (mCanvas != null) {
-                    setEnabled(true);
-                }
-            }
-        }
-
-        private boolean createSurface(Surface surface) {
-            mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, surface, null);
-
-            if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
-                int error = sEgl.eglGetError();
-                if (error == EGL_BAD_NATIVE_WINDOW) {
-                    Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
-                    return false;
-                }
-                throw new RuntimeException("createWindowSurface failed "
-                        + GLUtils.getEGLErrorString(error));
-            }
-
-            if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-                throw new IllegalStateException("eglMakeCurrent failed " +
-                        GLUtils.getEGLErrorString(sEgl.eglGetError()));
-            }
-
-            enableDirtyRegions();
-
-            return true;
-        }
-
-        @Override
-        boolean validate() {
-            return checkRenderContext() != SURFACE_STATE_ERROR;
-        }
-
-        @Override
-        void setup(int width, int height) {
-            if (validate()) {
-                mCanvas.setViewport(width, height);
-                mWidth = width;
-                mHeight = height;
-            }
-        }
-
-        @Override
-        int getWidth() {
-            return mWidth;
-        }
-
-        @Override
-        int getHeight() {
-            return mHeight;
-        }
-
-        @Override
-        HardwareCanvas getCanvas() {
-            return mCanvas;
-        }
-
-        @Override
-        void setName(String name) {
-            mName = name;
-        }
-
-        boolean canDraw() {
-            return mGl != null && mCanvas != null;
-        }
-
-        int onPreDraw(Rect dirty) {
-            return DisplayList.STATUS_DONE;
-        }
-
-        void onPostDraw() {
-        }
-
-        class FunctorsRunnable implements Runnable {
-            View.AttachInfo attachInfo;
-
-            @Override
-            public void run() {
-                final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
-                if (renderer == null || !renderer.isEnabled() || renderer != GlRenderer.this) {
-                    return;
-                }
-
-                if (checkRenderContext() != SURFACE_STATE_ERROR) {
-                    int status = mCanvas.invokeFunctors(mRedrawClip);
-                    handleFunctorStatus(attachInfo, status);
-                }
-            }
-        }
-
-        @Override
-        void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
-                Rect dirty) {
-            if (canDraw()) {
-                if (!hasDirtyRegions()) {
-                    dirty = null;
-                }
-                attachInfo.mIgnoreDirtyState = true;
-                attachInfo.mDrawingTime = SystemClock.uptimeMillis();
-
-                view.mPrivateFlags |= View.PFLAG_DRAWN;
-
-                // We are already on the correct thread
-                final int surfaceState = checkRenderContextUnsafe();
-                if (surfaceState != SURFACE_STATE_ERROR) {
-                    HardwareCanvas canvas = mCanvas;
-                    attachInfo.mHardwareCanvas = canvas;
-
-                    if (mProfileEnabled) {
-                        mProfileLock.lock();
-                    }
-
-                    dirty = beginFrame(canvas, dirty, surfaceState);
-
-                    DisplayList displayList = buildDisplayList(view, canvas);
-
-                    // buildDisplayList() calls into user code which can cause
-                    // an eglMakeCurrent to happen with a different surface/context.
-                    // We must therefore check again here.
-                    if (checkRenderContextUnsafe() == SURFACE_STATE_ERROR) {
-                        return;
-                    }
-
-                    int saveCount = 0;
-                    int status = DisplayList.STATUS_DONE;
-
-                    long start = getSystemTime();
-                    try {
-                        status = prepareFrame(dirty);
-
-                        saveCount = canvas.save();
-                        callbacks.onHardwarePreDraw(canvas);
-
-                        if (displayList != null) {
-                            status |= drawDisplayList(attachInfo, canvas, displayList, status);
-                        } else {
-                            // Shouldn't reach here
-                            view.draw(canvas);
-                        }
-                    } catch (Exception e) {
-                        Log.e(LOG_TAG, "An error has occurred while drawing:", e);
-                    } finally {
-                        callbacks.onHardwarePostDraw(canvas);
-                        canvas.restoreToCount(saveCount);
-                        view.mRecreateDisplayList = false;
-
-                        mDrawDelta = getSystemTime() - start;
-
-                        if (mDrawDelta > 0) {
-                            mFrameCount++;
-
-                            debugOverdraw(attachInfo, dirty, canvas, displayList);
-                            debugDirtyRegions(dirty, canvas);
-                            drawProfileData(attachInfo);
-                        }
-                    }
-
-                    onPostDraw();
-
-                    swapBuffers(status);
-
-                    if (mProfileEnabled) {
-                        mProfileLock.unlock();
-                    }
-
-                    attachInfo.mIgnoreDirtyState = false;
-                }
-            }
-        }
-
-        abstract void countOverdraw(HardwareCanvas canvas);
-        abstract float getOverdraw(HardwareCanvas canvas);
-
-        private void debugOverdraw(View.AttachInfo attachInfo, Rect dirty,
-                HardwareCanvas canvas, DisplayList displayList) {
-
-            if (mDebugOverdraw == OVERDRAW_TYPE_COUNT) {
-                if (mDebugOverdrawLayer == null) {
-                    mDebugOverdrawLayer = createHardwareLayer(mWidth, mHeight, true);
-                } else if (mDebugOverdrawLayer.getWidth() != mWidth ||
-                        mDebugOverdrawLayer.getHeight() != mHeight) {
-                    mDebugOverdrawLayer.resize(mWidth, mHeight);
-                }
-
-                if (!mDebugOverdrawLayer.isValid()) {
-                    mDebugOverdraw = -1;
-                    return;
-                }
-
-                HardwareCanvas layerCanvas = mDebugOverdrawLayer.start(canvas, dirty);
-                countOverdraw(layerCanvas);
-                final int restoreCount = layerCanvas.save();
-                layerCanvas.drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN);
-                layerCanvas.restoreToCount(restoreCount);
-                mDebugOverdrawLayer.end(canvas);
-
-                float overdraw = getOverdraw(layerCanvas);
-                DisplayMetrics metrics = attachInfo.mRootView.getResources().getDisplayMetrics();
-
-                drawOverdrawCounter(canvas, overdraw, metrics.density);
-            }
-        }
-
-        private void drawOverdrawCounter(HardwareCanvas canvas, float overdraw, float density) {
-            final String text = String.format("%.2fx", overdraw);
-            final Paint paint = setupPaint(density);
-            // HSBtoColor will clamp the values in the 0..1 range
-            paint.setColor(Color.HSBtoColor(0.28f - 0.28f * overdraw / 3.5f, 0.8f, 1.0f));
-
-            canvas.drawText(text, density * 4.0f, mHeight - paint.getFontMetrics().bottom, paint);
-        }
-
-        private Paint setupPaint(float density) {
-            if (mDebugOverdrawPaint == null) {
-                mDebugOverdrawPaint = new Paint();
-                mDebugOverdrawPaint.setAntiAlias(true);
-                mDebugOverdrawPaint.setShadowLayer(density * 3.0f, 0.0f, 0.0f, 0xff000000);
-                mDebugOverdrawPaint.setTextSize(density * 20.0f);
-            }
-            return mDebugOverdrawPaint;
-        }
-
-        private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
-            if (mDrawDelta <= 0) {
-                return view.mDisplayList;
-            }
-
-            view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
-                    == View.PFLAG_INVALIDATED;
-            view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
-            long buildDisplayListStartTime = startBuildDisplayListProfiling();
-            canvas.clearLayerUpdates();
-
-            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
-            DisplayList displayList = view.getDisplayList();
-            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-
-            endBuildDisplayListProfiling(buildDisplayListStartTime);
-
-            return displayList;
-        }
-
-        abstract void drawProfileData(View.AttachInfo attachInfo);
-
-        private Rect beginFrame(HardwareCanvas canvas, Rect dirty, int surfaceState) {
-            // We had to change the current surface and/or context, redraw everything
-            if (surfaceState == SURFACE_STATE_UPDATED) {
-                dirty = null;
-                beginFrame(null);
-            } else {
-                int[] size = mSurfaceSize;
-                beginFrame(size);
-
-                if (size[1] != mHeight || size[0] != mWidth) {
-                    mWidth = size[0];
-                    mHeight = size[1];
-
-                    canvas.setViewport(mWidth, mHeight);
-
-                    dirty = null;
-                }
-            }
-
-            if (mDebugDataProvider != null) dirty = null;
-
-            return dirty;
-        }
-
-        private long startBuildDisplayListProfiling() {
-            if (mProfileEnabled) {
-                mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
-                if (mProfileCurrentFrame >= mProfileData.length) {
-                    mProfileCurrentFrame = 0;
-                }
-
-                return System.nanoTime();
-            }
-            return 0;
-        }
-
-        private void endBuildDisplayListProfiling(long getDisplayListStartTime) {
-            if (mProfileEnabled) {
-                long now = System.nanoTime();
-                float total = (now - getDisplayListStartTime) * 0.000001f;
-                //noinspection PointlessArithmeticExpression
-                mProfileData[mProfileCurrentFrame] = total;
-            }
-        }
-
-        private int prepareFrame(Rect dirty) {
-            int status;
-            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
-            try {
-                status = onPreDraw(dirty);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-            }
-            return status;
-        }
-
-        private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas,
-                DisplayList displayList, int status) {
-
-            long drawDisplayListStartTime = 0;
-            if (mProfileEnabled) {
-                drawDisplayListStartTime = System.nanoTime();
-            }
-
-            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList");
-            try {
-                status |= canvas.drawDisplayList(displayList, mRedrawClip,
-                        DisplayList.FLAG_CLIP_CHILDREN);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-            }
-
-            if (mProfileEnabled) {
-                long now = System.nanoTime();
-                float total = (now - drawDisplayListStartTime) * 0.000001f;
-                mProfileData[mProfileCurrentFrame + 1] = total;
-            }
-
-            handleFunctorStatus(attachInfo, status);
-            return status;
-        }
-
-        private void swapBuffers(int status) {
-            if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) {
-                long eglSwapBuffersStartTime = 0;
-                if (mProfileEnabled) {
-                    eglSwapBuffersStartTime = System.nanoTime();
-                }
-
-                sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
-
-                if (mProfileEnabled) {
-                    long now = System.nanoTime();
-                    float total = (now - eglSwapBuffersStartTime) * 0.000001f;
-                    mProfileData[mProfileCurrentFrame + 2] = total;
-                }
-
-                checkEglErrors();
-            }
-        }
-
-        private void debugDirtyRegions(Rect dirty, HardwareCanvas canvas) {
-            if (mDebugDirtyRegions) {
-                if (mDebugPaint == null) {
-                    mDebugPaint = new Paint();
-                    mDebugPaint.setColor(0x7fff0000);
-                }
-
-                if (dirty != null && (mFrameCount & 1) == 0) {
-                    canvas.drawRect(dirty, mDebugPaint);
-                }
-            }
-        }
-
-        private void handleFunctorStatus(View.AttachInfo attachInfo, int status) {
-            // If the draw flag is set, functors will be invoked while executing
-            // the tree of display lists
-            if ((status & DisplayList.STATUS_DRAW) != 0) {
-                if (mRedrawClip.isEmpty()) {
-                    attachInfo.mViewRootImpl.invalidate();
-                } else {
-                    attachInfo.mViewRootImpl.invalidateChildInParent(null, mRedrawClip);
-                    mRedrawClip.setEmpty();
-                }
-            }
-
-            if ((status & DisplayList.STATUS_INVOKE) != 0 ||
-                    attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) {
-                attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
-                mFunctorsRunnable.attachInfo = attachInfo;
-                attachInfo.mHandler.postDelayed(mFunctorsRunnable, FUNCTOR_PROCESS_DELAY);
-            }
-        }
-
-        @Override
-        void detachFunctor(int functor) {
-            if (mCanvas != null) {
-                mCanvas.detachFunctor(functor);
-            }
-        }
-
-        @Override
-        boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
-            if (mCanvas != null) {
-                mCanvas.attachFunctor(functor);
-                mFunctorsRunnable.attachInfo = attachInfo;
-                attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
-                attachInfo.mHandler.postDelayed(mFunctorsRunnable,  0);
-                return true;
-            }
-            return false;
-        }
-
-        /**
-         * Ensures the current EGL context and surface are the ones we expect.
-         * This method throws an IllegalStateException if invoked from a thread
-         * that did not initialize EGL.
-         *
-         * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
-         *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
-         *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
-         *
-         * @see #checkRenderContextUnsafe()
-         */
-        int checkRenderContext() {
-            if (mEglThread != Thread.currentThread()) {
-                throw new IllegalStateException("Hardware acceleration can only be used with a " +
-                        "single UI thread.\nOriginal thread: " + mEglThread + "\n" +
-                        "Current thread: " + Thread.currentThread());
-            }
-
-            return checkRenderContextUnsafe();
-        }
-
-        /**
-         * Ensures the current EGL context and surface are the ones we expect.
-         * This method does not check the current thread.
-         *
-         * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
-         *         {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
-         *         {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
-         *
-         * @see #checkRenderContext()
-         */
-        private int checkRenderContextUnsafe() {
-            if (!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL_DRAW)) ||
-                    !mEglContext.equals(sEgl.eglGetCurrentContext())) {
-                if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-                    Log.e(LOG_TAG, "eglMakeCurrent failed " +
-                            GLUtils.getEGLErrorString(sEgl.eglGetError()));
-                    fallback(true);
-                    return SURFACE_STATE_ERROR;
-                } else {
-                    if (mUpdateDirtyRegions) {
-                        enableDirtyRegions();
-                        mUpdateDirtyRegions = false;
-                    }
-                    return SURFACE_STATE_UPDATED;
-                }
-            }
-            return SURFACE_STATE_SUCCESS;
-        }
-
-        private static int dpToPx(int dp, float density) {
-            return (int) (dp * density + 0.5f);
-        }
-
-        class DrawPerformanceDataProvider extends GraphDataProvider {
-            private final int mGraphType;
-
-            private int mVerticalUnit;
-            private int mHorizontalUnit;
-            private int mHorizontalMargin;
-            private int mThresholdStroke;
-
-            DrawPerformanceDataProvider(int graphType) {
-                mGraphType = graphType;
-            }
-
-            @Override
-            void prepare(DisplayMetrics metrics) {
-                final float density = metrics.density;
-
-                mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
-                mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
-                mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
-                mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
-            }
-
-            @Override
-            int getGraphType() {
-                return mGraphType;
-            }
-
-            @Override
-            int getVerticalUnitSize() {
-                return mVerticalUnit;
-            }
-
-            @Override
-            int getHorizontalUnitSize() {
-                return mHorizontalUnit;
-            }
-
-            @Override
-            int getHorizontaUnitMargin() {
-                return mHorizontalMargin;
-            }
-
-            @Override
-            float[] getData() {
-                return mProfileData;
-            }
-
-            @Override
-            float getThreshold() {
-                return 16;
-            }
-
-            @Override
-            int getFrameCount() {
-                return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
-            }
-
-            @Override
-            int getElementCount() {
-                return PROFILE_FRAME_DATA_COUNT;
-            }
-
-            @Override
-            int getCurrentFrame() {
-                return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
-            }
-
-            @Override
-            void setupGraphPaint(Paint paint, int elementIndex) {
-                paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
-                if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
-            }
-
-            @Override
-            void setupThresholdPaint(Paint paint) {
-                paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
-                paint.setStrokeWidth(mThresholdStroke);
-            }
-
-            @Override
-            void setupCurrentFramePaint(Paint paint) {
-                paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
-                if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
-            }
-        }
-    }
-
-    /**
-     * Hardware renderer using OpenGL ES 2.0.
-     */
-    static class Gl20Renderer extends GlRenderer {
-        private GLES20Canvas mGlCanvas;
-
-        private DisplayMetrics mDisplayMetrics;
-
-        private static EGLSurface sPbuffer;
-        private static final Object[] sPbufferLock = new Object[0];
-
-        static class Gl20RendererEglContext extends ManagedEGLContext {
-            final Handler mHandler = new Handler();
-
-            public Gl20RendererEglContext(EGLContext context) {
-                super(context);
-            }
-
-            @Override
-            public void onTerminate(final EGLContext eglContext) {
-                // Make sure we do this on the correct thread.
-                if (mHandler.getLooper() != Looper.myLooper()) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            onTerminate(eglContext);
-                        }
-                    });
-                    return;
-                }
-
-                synchronized (sEglLock) {
-                    if (sEgl == null) return;
-
-                    if (EGLImpl.getInitCount(sEglDisplay) == 1) {
-                        usePbufferSurface(eglContext);
-                        GLES20Canvas.terminateCaches();
-
-                        sEgl.eglDestroyContext(sEglDisplay, eglContext);
-                        sEglContextStorage.set(null);
-                        sEglContextStorage.remove();
-
-                        sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
-                        sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
-                                EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-                        sEgl.eglReleaseThread();
-                        sEgl.eglTerminate(sEglDisplay);
-
-                        sEgl = null;
-                        sEglDisplay = null;
-                        sEglConfig = null;
-                        sPbuffer = null;
-                    }
-                }
-            }
-        }
-
-        Gl20Renderer(boolean translucent) {
-            super(2, translucent);
-        }
-
-        @Override
-        HardwareCanvas createCanvas() {
-            return mGlCanvas = new GLES20Canvas(mTranslucent);
-        }
-
-        @Override
-        ManagedEGLContext createManagedContext(EGLContext eglContext) {
-            return new Gl20Renderer.Gl20RendererEglContext(mEglContext);
-        }
-
-        @Override
-        int[] getConfig(boolean dirtyRegions) {
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            final int stencilSize = GLES20Canvas.getStencilSize();
-            final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
-
-            return new int[] {
-                    EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
-                    EGL_RED_SIZE, 8,
-                    EGL_GREEN_SIZE, 8,
-                    EGL_BLUE_SIZE, 8,
-                    EGL_ALPHA_SIZE, 8,
-                    EGL_DEPTH_SIZE, 0,
-                    EGL_CONFIG_CAVEAT, EGL_NONE,
-                    EGL_STENCIL_SIZE, stencilSize,
-                    EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
-                    EGL_NONE
-            };
-        }
-
-        @Override
-        void initCaches() {
-            if (GLES20Canvas.initCaches()) {
-                // Caches were (re)initialized, rebind atlas
-                initAtlas();
-            }
-        }
-
-        @Override
-        void initAtlas() {
-            IBinder binder = ServiceManager.getService("assetatlas");
-            if (binder == null) return;
-
-            IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
-            try {
-                if (atlas.isCompatible(android.os.Process.myPpid())) {
-                    GraphicBuffer buffer = atlas.getBuffer();
-                    if (buffer != null) {
-                        int[] map = atlas.getMap();
-                        if (map != null) {
-                            GLES20Canvas.initAtlas(buffer, map);
-                        }
-                        // If IAssetAtlas is not the same class as the IBinder
-                        // we are using a remote service and we can safely
-                        // destroy the graphic buffer
-                        if (atlas.getClass() != binder.getClass()) {
-                            buffer.destroy();
-                        }
-                    }
-                }
-            } catch (RemoteException e) {
-                Log.w(LOG_TAG, "Could not acquire atlas", e);
-            }
-        }
-
-        @Override
-        boolean canDraw() {
-            return super.canDraw() && mGlCanvas != null;
-        }
-
-        @Override
-        int onPreDraw(Rect dirty) {
-            return mGlCanvas.onPreDraw(dirty);
-        }
-
-        @Override
-        void onPostDraw() {
-            mGlCanvas.onPostDraw();
-        }
-
-        @Override
-        void drawProfileData(View.AttachInfo attachInfo) {
-            if (mDebugDataProvider != null) {
-                final GraphDataProvider provider = mDebugDataProvider;
-                initProfileDrawData(attachInfo, provider);
-
-                final int height = provider.getVerticalUnitSize();
-                final int margin = provider.getHorizontaUnitMargin();
-                final int width = provider.getHorizontalUnitSize();
-
-                int x = 0;
-                int count = 0;
-                int current = 0;
-
-                final float[] data = provider.getData();
-                final int elementCount = provider.getElementCount();
-                final int graphType = provider.getGraphType();
-
-                int totalCount = provider.getFrameCount() * elementCount;
-                if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
-                    totalCount -= elementCount;
-                }
-
-                for (int i = 0; i < totalCount; i += elementCount) {
-                    if (data[i] < 0.0f) break;
-
-                    int index = count * 4;
-                    if (i == provider.getCurrentFrame() * elementCount) current = index;
-
-                    x += margin;
-                    int x2 = x + width;
-
-                    int y2 = mHeight;
-                    int y1 = (int) (y2 - data[i] * height);
-
-                    switch (graphType) {
-                        case GraphDataProvider.GRAPH_TYPE_BARS: {
-                            for (int j = 0; j < elementCount; j++) {
-                                //noinspection MismatchedReadAndWriteOfArray
-                                final float[] r = mProfileShapes[j];
-                                r[index] = x;
-                                r[index + 1] = y1;
-                                r[index + 2] = x2;
-                                r[index + 3] = y2;
-
-                                y2 = y1;
-                                if (j < elementCount - 1) {
-                                    y1 = (int) (y2 - data[i + j + 1] * height);
-                                }
-                            }
-                        } break;
-                        case GraphDataProvider.GRAPH_TYPE_LINES: {
-                            for (int j = 0; j < elementCount; j++) {
-                                //noinspection MismatchedReadAndWriteOfArray
-                                final float[] r = mProfileShapes[j];
-                                r[index] = (x + x2) * 0.5f;
-                                r[index + 1] = index == 0 ? y1 : r[index - 1];
-                                r[index + 2] = r[index] + width;
-                                r[index + 3] = y1;
-
-                                y2 = y1;
-                                if (j < elementCount - 1) {
-                                    y1 = (int) (y2 - data[i + j + 1] * height);
-                                }
-                            }
-                        } break;
-                    }
-
-
-                    x += width;
-                    count++;
-                }
-
-                x += margin;
-
-                drawGraph(graphType, count);
-                drawCurrentFrame(graphType, current);
-                drawThreshold(x, height);
-            }
-        }
-
-        private void drawGraph(int graphType, int count) {
-            for (int i = 0; i < mProfileShapes.length; i++) {
-                mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
-                switch (graphType) {
-                    case GraphDataProvider.GRAPH_TYPE_BARS:
-                        mGlCanvas.drawRects(mProfileShapes[i], count * 4, mProfilePaint);
-                        break;
-                    case GraphDataProvider.GRAPH_TYPE_LINES:
-                        mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
-                        break;
-                }
-            }
-        }
-
-        private void drawCurrentFrame(int graphType, int index) {
-            if (index >= 0) {
-                mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
-                switch (graphType) {
-                    case GraphDataProvider.GRAPH_TYPE_BARS:
-                        mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
-                                mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
-                                mProfilePaint);
-                        break;
-                    case GraphDataProvider.GRAPH_TYPE_LINES:
-                        mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
-                                mProfileShapes[2][index], mHeight, mProfilePaint);
-                        break;
-                }
-            }
-        }
-
-        private void drawThreshold(int x, int height) {
-            float threshold = mDebugDataProvider.getThreshold();
-            if (threshold > 0.0f) {
-                mDebugDataProvider.setupThresholdPaint(mProfilePaint);
-                int y = (int) (mHeight - threshold * height);
-                mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
-            }
-        }
-
-        private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
-            if (mProfileShapes == null) {
-                final int elementCount = provider.getElementCount();
-                final int frameCount = provider.getFrameCount();
-
-                mProfileShapes = new float[elementCount][];
-                for (int i = 0; i < elementCount; i++) {
-                    mProfileShapes[i] = new float[frameCount * 4];
-                }
-
-                mProfilePaint = new Paint();
-            }
-
-            mProfilePaint.reset();
-            if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
-                mProfilePaint.setAntiAlias(true);
-            }
-
-            if (mDisplayMetrics == null) {
-                mDisplayMetrics = new DisplayMetrics();
-            }
-
-            attachInfo.mDisplay.getMetrics(mDisplayMetrics);
-            provider.prepare(mDisplayMetrics);
-        }
-
-        @Override
-        void destroy(boolean full) {
-            try {
-                super.destroy(full);
-            } finally {
-                if (full && mGlCanvas != null) {
-                    mGlCanvas = null;
-                }
-            }
-        }
-
-        @Override
-        void pushLayerUpdate(HardwareLayer layer) {
-            mGlCanvas.pushLayerUpdate(layer);
-        }
-
-        @Override
-        void cancelLayerUpdate(HardwareLayer layer) {
-            mGlCanvas.cancelLayerUpdate(layer);
-        }
-
-        @Override
-        void flushLayerUpdates() {
-            mGlCanvas.flushLayerUpdates();
-        }
-
-        @Override
-        public DisplayList createDisplayList(String name) {
-            return new GLES20DisplayList(name);
-        }
-
-        @Override
-        HardwareLayer createHardwareLayer(boolean isOpaque) {
-            return new GLES20TextureLayer(isOpaque);
-        }
-
-        @Override
-        public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
-            return new GLES20RenderLayer(width, height, isOpaque);
-        }
-
-        @Override
-        void countOverdraw(HardwareCanvas canvas) {
-            ((GLES20Canvas) canvas).setCountOverdrawEnabled(true);
-        }
-
-        @Override
-        float getOverdraw(HardwareCanvas canvas) {
-            return ((GLES20Canvas) canvas).getOverdraw();
-        }
-
-        @Override
-        public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
-            return ((GLES20TextureLayer) layer).getSurfaceTexture();
-        }
-
-        @Override
-        void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
-            ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
-        }
-
-        @Override
-        boolean safelyRun(Runnable action) {
-            boolean needsContext = !isEnabled() || checkRenderContext() == SURFACE_STATE_ERROR;
-
-            if (needsContext) {
-                Gl20RendererEglContext managedContext =
-                        (Gl20RendererEglContext) sEglContextStorage.get();
-                if (managedContext == null) return false;
-                usePbufferSurface(managedContext.getContext());
-            }
-
-            try {
-                action.run();
-            } finally {
-                if (needsContext) {
-                    sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE,
-                            EGL_NO_SURFACE, EGL_NO_CONTEXT);
-                }
-            }
-
-            return true;
-        }
-
-        @Override
-        void destroyLayers(final View view) {
-            if (view != null) {
-                safelyRun(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (mCanvas != null) {
-                            mCanvas.clearLayerUpdates();
-                        }
-                        destroyHardwareLayer(view);
-                        GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
-                    }
-                });
-            }
-        }
-
-        private static void destroyHardwareLayer(View view) {
-            view.destroyLayer(true);
-
-            if (view instanceof ViewGroup) {
-                ViewGroup group = (ViewGroup) view;
-
-                int count = group.getChildCount();
-                for (int i = 0; i < count; i++) {
-                    destroyHardwareLayer(group.getChildAt(i));
-                }
-            }
-        }
-
-        @Override
-        void destroyHardwareResources(final View view) {
-            if (view != null) {
-                safelyRun(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (mCanvas != null) {
-                            mCanvas.clearLayerUpdates();
-                        }
-                        destroyResources(view);
-                        GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
-                    }
-                });
-            }
-        }
-
-        private static void destroyResources(View view) {
-            view.destroyHardwareResources();
-
-            if (view instanceof ViewGroup) {
-                ViewGroup group = (ViewGroup) view;
-
-                int count = group.getChildCount();
-                for (int i = 0; i < count; i++) {
-                    destroyResources(group.getChildAt(i));
-                }
-            }
-        }
-
-        static HardwareRenderer create(boolean translucent) {
-            if (GLES20Canvas.isAvailable()) {
-                return new Gl20Renderer(translucent);
-            }
-            return null;
-        }
-
-        static void startTrimMemory(int level) {
-            if (sEgl == null || sEglConfig == null) return;
-
-            Gl20RendererEglContext managedContext =
-                    (Gl20RendererEglContext) sEglContextStorage.get();
-            // We do not have OpenGL objects
-            if (managedContext == null) {
-                return;
-            } else {
-                usePbufferSurface(managedContext.getContext());
-            }
-
-            if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
-                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
-            } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
-                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
-            }
-        }
-
-        static void endTrimMemory() {
-            if (sEgl != null && sEglDisplay != null) {
-                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            }
-        }
-
-        private static void usePbufferSurface(EGLContext eglContext) {
-            synchronized (sPbufferLock) {
-                // Create a temporary 1x1 pbuffer so we have a context
-                // to clear our OpenGL objects
-                if (sPbuffer == null) {
-                    sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
-                            EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
-                    });
-                }
-            }
-            sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
-        }
-    }
 }
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/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b22d5cf..a06a20b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -79,9 +79,6 @@
     private final String mName;
     int mNativeObject; // package visibility only for Surface.java access
 
-    private static final boolean HEADLESS = "1".equals(
-        SystemProperties.get("ro.config.headless", "0"));
-
     /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
 
     /**
@@ -232,8 +229,6 @@
                     new Throwable());
         }
 
-        checkHeadless();
-
         mName = name;
         mNativeObject = nativeCreate(session, name, w, h, format, flags);
         if (mNativeObject == 0) {
@@ -619,10 +614,4 @@
         }
         nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers);
     }
-
-    private static void checkHeadless() {
-        if (HEADLESS) {
-            throw new UnsupportedOperationException("Device is headless");
-        }
-    }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1c3688d..fc95724 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 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;
@@ -3197,6 +3196,16 @@
     private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
 
     /**
+     * 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
      */
     int mOldWidthMeasureSpec = Integer.MIN_VALUE;
@@ -3661,10 +3670,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;
 
@@ -3996,6 +4005,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;
@@ -4013,11 +4027,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;
@@ -4029,10 +4043,10 @@
             // defined.
             final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined;
 
-            if (leftPaddingDefined && !hasRelativePadding) {
+            if (mLeftPaddingDefined && !hasRelativePadding) {
                 mUserPaddingLeftInitial = leftPadding;
             }
-            if (rightPaddingDefined && !hasRelativePadding) {
+            if (mRightPaddingDefined && !hasRelativePadding) {
                 mUserPaddingRightInitial = rightPadding;
             }
         }
@@ -6033,6 +6047,8 @@
                 sThreadLocal.set(localInsets);
             }
             boolean res = computeFitSystemWindows(insets, localInsets);
+            mUserPaddingLeftInitial = localInsets.left;
+            mUserPaddingRightInitial = localInsets.right;
             internalSetPadding(localInsets.left, localInsets.top,
                     localInsets.right, localInsets.bottom);
             return res;
@@ -10942,15 +10958,6 @@
             mPrivateFlags |= PFLAG_DIRTY;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
-                if (p != null && ai != null && ai.mHardwareAccelerated) {
-                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
-                    p.invalidateChild(this, null);
-                    return;
-                }
-            }
             if (p != null && ai != null) {
                 final int scrollX = mScrollX;
                 final int scrollY = mScrollY;
@@ -10985,15 +10992,6 @@
             mPrivateFlags |= PFLAG_DIRTY;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
-                if (p != null && ai != null && ai.mHardwareAccelerated) {
-                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
-                    p.invalidateChild(this, null);
-                    return;
-                }
-            }
             if (p != null && ai != null && l < r && t < b) {
                 final int scrollX = mScrollX;
                 final int scrollY = mScrollY;
@@ -11041,15 +11039,6 @@
             }
             final AttachInfo ai = mAttachInfo;
             final ViewParent p = mParent;
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
-                if (p != null && ai != null && ai.mHardwareAccelerated) {
-                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
-                    p.invalidateChild(this, null);
-                    return;
-                }
-            }
 
             if (p != null && ai != null) {
                 final Rect r = ai.mTmpInvalRect;
@@ -12274,12 +12263,14 @@
         if (!isTextAlignmentResolved()) {
             resolveTextAlignment();
         }
-        if (!isPaddingResolved()) {
-            resolvePadding();
-        }
+        // Should resolve Drawables before Padding because we need the layout direction of the
+        // Drawable to correctly resolve Padding.
         if (!isDrawablesResolved()) {
             resolveDrawables();
         }
+        if (!isPaddingResolved()) {
+            resolvePadding();
+        }
         onRtlPropertiesChanged(getLayoutDirection());
         return true;
     }
@@ -12482,6 +12473,20 @@
             // 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 && (!mLeftPaddingDefined || !mRightPaddingDefined)) {
+                Rect padding = sThreadLocal.get();
+                if (padding == null) {
+                    padding = new Rect();
+                    sThreadLocal.set(padding);
+                }
+                mBackground.getPadding(padding);
+                if (!mLeftPaddingDefined) {
+                    mUserPaddingLeftInitial = padding.left;
+                }
+                if (!mRightPaddingDefined) {
+                    mUserPaddingRightInitial = padding.right;
+                }
+            }
             switch (resolvedLayoutDirection) {
                 case LAYOUT_DIRECTION_RTL:
                     if (mUserPaddingStart != UNDEFINED_PADDING) {
@@ -13369,20 +13374,6 @@
     }
 
     /**
-     * @return The {@link HardwareRenderer} associated with that view or null if
-     *         hardware rendering is not supported or this view is not attached
-     *         to a window.
-     *
-     * @hide
-     */
-    public HardwareRenderer getHardwareRenderer() {
-        if (mAttachInfo != null) {
-            return mAttachInfo.mHardwareRenderer;
-        }
-        return null;
-    }
-
-    /**
      * Returns a DisplayList. If the incoming displayList is null, one will be created.
      * Otherwise, the same display list will be returned (after having been rendered into
      * along the way, depending on the invalidation state of the view).
@@ -13417,7 +13408,7 @@
                 mRecreateDisplayList = true;
             }
             if (displayList == null) {
-                displayList = mAttachInfo.mHardwareRenderer.createDisplayList(getClass().getName());
+                displayList = DisplayList.create(getClass().getName());
                 // If we're creating a new display list, make sure our parent gets invalidated
                 // since they will need to recreate their display list to account for this
                 // new child display list.
@@ -15477,6 +15468,8 @@
                         mUserPaddingRightInitial = padding.right;
                         internalSetPadding(padding.left, padding.top, padding.right, padding.bottom);
                 }
+                mLeftPaddingDefined = false;
+                mRightPaddingDefined = false;
             }
 
             // Compare the minimum sizes of the old Drawable and the new.  If there isn't an old or
@@ -15573,6 +15566,9 @@
         mUserPaddingLeftInitial = left;
         mUserPaddingRightInitial = right;
 
+        mLeftPaddingDefined = true;
+        mRightPaddingDefined = true;
+
         internalSetPadding(left, top, right, bottom);
     }
 
@@ -15658,6 +15654,8 @@
 
         mUserPaddingStart = start;
         mUserPaddingEnd = end;
+        mLeftPaddingDefined = true;
+        mRightPaddingDefined = true;
 
         switch(getLayoutDirection()) {
             case LAYOUT_DIRECTION_RTL:
@@ -18850,7 +18848,6 @@
         View mRootView;
 
         IBinder mPanelParentWindowToken;
-        Surface mSurface;
 
         boolean mHardwareAccelerated;
         boolean mHardwareAccelerationRequested;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 01eec98..dd2baf6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2511,13 +2511,13 @@
     void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
         if (mAttachInfo != null) {
-            ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
+            final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
             childrenForAccessibility.clear();
             addChildrenForAccessibility(childrenForAccessibility);
             final int childrenForAccessibilityCount = childrenForAccessibility.size();
             for (int i = 0; i < childrenForAccessibilityCount; i++) {
-                View child = childrenForAccessibility.get(i);
-                info.addChild(child);
+                final View child = childrenForAccessibility.get(i);
+                info.addChildUnchecked(child);
             }
             childrenForAccessibility.clear();
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 17bb169..a5f797e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -108,7 +108,6 @@
     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
     private static final boolean DEBUG_FPS = false;
-    private static final boolean DEBUG_INPUT_PROCESSING = false || LOCAL_LOGV;
 
     /**
      * Set this system property to true to force the view hierarchy to render
@@ -719,7 +718,7 @@
                 }
 
                 final boolean translucent = attrs.format != PixelFormat.OPAQUE;
-                mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
+                mAttachInfo.mHardwareRenderer = HardwareRenderer.create(translucent);
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
                     mAttachInfo.mHardwareAccelerated =
@@ -1195,11 +1194,6 @@
                 desiredWindowHeight = packageMetrics.heightPixels;
             }
 
-            // For the very first time, tell the view hierarchy that it
-            // is attached to the window.  Note that at this point the surface
-            // object is not initialized to its backing store, but soon it
-            // will be (assuming the window is visible).
-            attachInfo.mSurface = mSurface;
             // We used to use the following condition to choose 32 bits drawing caches:
             // PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
             // However, windows are now always 32 bits by default, so choose 32 bits
@@ -1548,7 +1542,7 @@
                         if (mAttachInfo.mHardwareRenderer != null) {
                             try {
                                 hwInitialized = mAttachInfo.mHardwareRenderer.initialize(
-                                        mHolder.getSurface());
+                                        mSurface);
                             } catch (OutOfResourcesException e) {
                                 handleOutOfResourcesException(e);
                                 return;
@@ -1575,7 +1569,7 @@
                         mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
                     mFullRedrawNeeded = true;
                     try {
-                        mAttachInfo.mHardwareRenderer.updateSurface(mHolder.getSurface());
+                        mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
                     } catch (OutOfResourcesException e) {
                         handleOutOfResourcesException(e);
                         return;
@@ -1658,7 +1652,7 @@
                         mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
                     mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
                     if (!hwInitialized) {
-                        mAttachInfo.mHardwareRenderer.invalidate(mHolder.getSurface());
+                        mAttachInfo.mHardwareRenderer.invalidate(mSurface);
                         mFullRedrawNeeded = true;
                     }
                 }
@@ -2395,7 +2389,7 @@
 
                     try {
                         attachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
-                                mHolder.getSurface());
+                                mSurface);
                     } catch (OutOfResourcesException e) {
                         handleOutOfResourcesException(e);
                         return;
@@ -2857,7 +2851,6 @@
         mView.assignParent(null);
         mView = null;
         mAttachInfo.mRootView = null;
-        mAttachInfo.mSurface = null;
 
         mSurface.release();
 
@@ -3117,7 +3110,7 @@
                             mFullRedrawNeeded = true;
                             try {
                                 mAttachInfo.mHardwareRenderer.initializeIfNeeded(
-                                        mWidth, mHeight, mHolder.getSurface());
+                                        mWidth, mHeight, mSurface);
                             } catch (OutOfResourcesException e) {
                                 Log.e(TAG, "OutOfResourcesException locking surface", e);
                                 try {
@@ -4511,8 +4504,7 @@
         // The active pointer id, or -1 if none.
         private int mActivePointerId = -1;
 
-        // Time and location where tracking started.
-        private long mStartTime;
+        // Location where tracking started.
         private float mStartX;
         private float mStartY;
 
@@ -4540,9 +4532,6 @@
         private boolean mFlinging;
         private float mFlingVelocity;
 
-        // The last time a confirm key was pressed on the touch nav device
-        private long mLastConfirmKeyTime = Long.MAX_VALUE;
-
         public SyntheticTouchNavigationHandler() {
             super(true);
         }
@@ -4609,7 +4598,6 @@
                     mActivePointerId = event.getPointerId(0);
                     mVelocityTracker = VelocityTracker.obtain();
                     mVelocityTracker.addMovement(event);
-                    mStartTime = time;
                     mStartX = event.getX();
                     mStartY = event.getY();
                     mLastX = mStartX;
@@ -5393,7 +5381,7 @@
 
                 // Hardware rendering
                 if (mAttachInfo.mHardwareRenderer != null) {
-                    if (mAttachInfo.mHardwareRenderer.loadSystemProperties(mHolder.getSurface())) {
+                    if (mAttachInfo.mHardwareRenderer.loadSystemProperties(mSurface)) {
                         invalidate();
                     }
                 }
@@ -6340,68 +6328,6 @@
         }
     }
 
-    private final SurfaceHolder mHolder = new SurfaceHolder() {
-        // we only need a SurfaceHolder for opengl. it would be nice
-        // to implement everything else though, especially the callback
-        // support (opengl doesn't make use of it right now, but eventually
-        // will).
-        @Override
-        public Surface getSurface() {
-            return mSurface;
-        }
-
-        @Override
-        public boolean isCreating() {
-            return false;
-        }
-
-        @Override
-        public void addCallback(Callback callback) {
-        }
-
-        @Override
-        public void removeCallback(Callback callback) {
-        }
-
-        @Override
-        public void setFixedSize(int width, int height) {
-        }
-
-        @Override
-        public void setSizeFromLayout() {
-        }
-
-        @Override
-        public void setFormat(int format) {
-        }
-
-        @Override
-        public void setType(int type) {
-        }
-
-        @Override
-        public void setKeepScreenOn(boolean screenOn) {
-        }
-
-        @Override
-        public Canvas lockCanvas() {
-            return null;
-        }
-
-        @Override
-        public Canvas lockCanvas(Rect dirty) {
-            return null;
-        }
-
-        @Override
-        public void unlockCanvasAndPost(Canvas canvas) {
-        }
-        @Override
-        public Rect getSurfaceFrame() {
-            return null;
-        }
-    };
-
     static RunQueue getRunQueue() {
         RunQueue rq = sRunQueues.get();
         if (rq != null) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a940f73..11d8d36 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -91,12 +91,21 @@
      * If overlay is enabled, the action mode UI will be allowed to cover existing window content.
      */
     public static final int FEATURE_ACTION_MODE_OVERLAY = 10;
+    /**
+     * Flag for requesting that window content changes should be represented
+     * with scenes and transitions.
+     *
+     * TODO Add docs
+     *
+     * @see #setContentView
+     */
+    public static final int FEATURE_CONTENT_TRANSITIONS = 11;
 
     /**
      * Max value used as a feature ID
      * @hide
      */
-    public static final int FEATURE_MAX = FEATURE_ACTION_MODE_OVERLAY;
+    public static final int FEATURE_MAX = FEATURE_CONTENT_TRANSITIONS;
 
     /** Flag for setting the progress bar's visibility to VISIBLE */
     public static final int PROGRESS_VISIBILITY_ON = -1;
@@ -987,6 +996,7 @@
 
     public abstract void setTitle(CharSequence title);
 
+    @Deprecated
     public abstract void setTitleColor(int textColor);
 
     public abstract void openPanel(int featureId, KeyEvent event);
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 139df3e..d6e40aec 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -718,10 +718,9 @@
                 Log.e(LOG_TAG, "Duplicate node.");
                 return;
             }
-            SparseLongArray childIds = current.getChildNodeIds();
-            final int childCount = childIds.size();
+            final int childCount = current.getChildCount();
             for (int i = 0; i < childCount; i++) {
-                final long childId = childIds.valueAt(i);
+                final long childId = current.getChildId(i);
                 for (int j = 0; j < infoCount; j++) {
                     AccessibilityNodeInfo child = infos.get(j);
                     if (child.getSourceNodeId() == childId) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4f53c1e..61aabea 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -22,8 +22,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.InputType;
+import android.util.LongArray;
 import android.util.Pools.SynchronizedPool;
-import android.util.SparseLongArray;
 import android.view.View;
 
 import java.util.Collections;
@@ -503,7 +503,7 @@
     private CharSequence mContentDescription;
     private String mViewIdResourceName;
 
-    private final SparseLongArray mChildNodeIds = new SparseLongArray();
+    private LongArray mChildNodeIds;
     private int mActions;
 
     private int mMovementGranularities;
@@ -666,21 +666,35 @@
     }
 
     /**
-     * @return The ids of the children.
+     * Returns the array containing the IDs of this node's children.
      *
      * @hide
      */
-    public SparseLongArray getChildNodeIds() {
+    public LongArray getChildNodeIds() {
         return mChildNodeIds;
     }
 
     /**
+     * Returns the id of the child at the specified index.
+     *
+     * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
+     *             getChildCount()
+     * @hide
+     */
+    public long getChildId(int index) {
+        if (mChildNodeIds == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mChildNodeIds.get(index);
+    }
+
+    /**
      * Gets the number of children.
      *
      * @return The child count.
      */
     public int getChildCount() {
-        return mChildNodeIds.size();
+        return mChildNodeIds == null ? 0 : mChildNodeIds.size();
     }
 
     /**
@@ -699,6 +713,9 @@
      */
     public AccessibilityNodeInfo getChild(int index) {
         enforceSealed();
+        if (mChildNodeIds == null) {
+            return null;
+        }
         if (!canPerformRequestOverConnection(mSourceNodeId)) {
             return null;
         }
@@ -721,7 +738,35 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void addChild(View child) {
-        addChild(child, UNDEFINED);
+        addChildInternal(child, UNDEFINED, true);
+    }
+
+    /**
+     * Unchecked version of {@link #addChild(View)} that does not verify
+     * uniqueness. For framework use only.
+     *
+     * @hide
+     */
+    public void addChildUnchecked(View child) {
+        addChildInternal(child, UNDEFINED, false);
+    }
+
+    /**
+     * Removes a child. If the child was not previously added to the node,
+     * calling this method has no effect.
+     * <p>
+     * <strong>Note:</strong> Cannot be called from an
+     * {@link android.accessibilityservice.AccessibilityService}.
+     * This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param child The child.
+     * @return true if the child was present
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public boolean removeChild(View child) {
+        return removeChild(child, UNDEFINED);
     }
 
     /**
@@ -739,12 +784,49 @@
      * @param virtualDescendantId The id of the virtual child.
      */
     public void addChild(View root, int virtualDescendantId) {
+        addChildInternal(root, virtualDescendantId, true);
+    }
+
+    private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
         enforceNotSealed();
-        final int index = mChildNodeIds.size();
+        if (mChildNodeIds == null) {
+            mChildNodeIds = new LongArray();
+        }
         final int rootAccessibilityViewId =
             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
-        mChildNodeIds.put(index, childNodeId);
+        // If we're checking uniqueness and the ID already exists, abort.
+        if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
+            return;
+        }
+        mChildNodeIds.add(childNodeId);
+    }
+
+    /**
+     * Removes a virtual child which is a descendant of the given
+     * <code>root</code>. If the child was not previously added to the node,
+     * calling this method has no effect.
+     *
+     * @param root The root of the virtual subtree.
+     * @param virtualDescendantId The id of the virtual child.
+     * @return true if the child was present
+     * @see #addChild(View, int)
+     */
+    public boolean removeChild(View root, int virtualDescendantId) {
+        enforceNotSealed();
+        final LongArray childIds = mChildNodeIds;
+        if (childIds == null) {
+            return false;
+        }
+        final int rootAccessibilityViewId =
+                (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
+        final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+        final int index = childIds.indexOf(childNodeId);
+        if (index < 0) {
+            return false;
+        }
+        childIds.remove(index);
+        return true;
     }
 
     /**
@@ -789,6 +871,24 @@
     }
 
     /**
+     * Removes an action that can be performed on the node. If the action was
+     * not already added to the node, calling this method has no effect.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param action The action.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void removeAction(int action) {
+        enforceNotSealed();
+        mActions &= ~action;
+    }
+
+    /**
      * Sets the movement granularities for traversing the text of this node.
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
@@ -1408,8 +1508,6 @@
      *   {@link android.accessibilityservice.AccessibilityService}.
      *   This class is made immutable before being delivered to an AccessibilityService.
      * </p>
-     *
-     * @return collectionItem True if the node is an item.
      */
     public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
         enforceNotSealed();
@@ -1951,6 +2049,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public int describeContents() {
         return 0;
     }
@@ -2114,6 +2213,7 @@
      *      is recycled. You must not touch the object after calling this function.
      * </p>
      */
+    @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(isSealed() ? 1 : 0);
         parcel.writeLong(mSourceNodeId);
@@ -2123,11 +2223,15 @@
         parcel.writeLong(mLabeledById);
         parcel.writeInt(mConnectionId);
 
-        SparseLongArray childIds = mChildNodeIds;
-        final int childIdsSize = childIds.size();
-        parcel.writeInt(childIdsSize);
-        for (int i = 0; i < childIdsSize; i++) {
-            parcel.writeLong(childIds.valueAt(i));
+        final LongArray childIds = mChildNodeIds;
+        if (childIds == null) {
+            parcel.writeInt(0);
+        } else {
+            final int childIdsSize = childIds.size();
+            parcel.writeInt(childIdsSize);
+            for (int i = 0; i < childIdsSize; i++) {
+                parcel.writeLong(childIds.get(i));
+            }
         }
 
         parcel.writeInt(mBoundsInParent.top);
@@ -2222,10 +2326,16 @@
         mActions= other.mActions;
         mBooleanProperties = other.mBooleanProperties;
         mMovementGranularities = other.mMovementGranularities;
-        final int otherChildIdCount = other.mChildNodeIds.size();
-        for (int i = 0; i < otherChildIdCount; i++) {
-            mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
+
+        final LongArray otherChildNodeIds = other.mChildNodeIds;
+        if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
+            if (mChildNodeIds == null) {
+                mChildNodeIds = otherChildNodeIds.clone();
+            } else {
+                mChildNodeIds.addAll(otherChildNodeIds);
+            }
         }
+
         mTextSelectionStart = other.mTextSelectionStart;
         mTextSelectionEnd = other.mTextSelectionEnd;
         mInputType = other.mInputType;
@@ -2255,11 +2365,15 @@
         mLabeledById = parcel.readLong();
         mConnectionId = parcel.readInt();
 
-        SparseLongArray childIds = mChildNodeIds;
         final int childrenSize = parcel.readInt();
-        for (int i = 0; i < childrenSize; i++) {
-            final long childId = parcel.readLong();
-            childIds.put(i, childId);
+        if (childrenSize <= 0) {
+            mChildNodeIds = null;
+        } else {
+            mChildNodeIds = new LongArray(childrenSize);
+            for (int i = 0; i < childrenSize; i++) {
+                final long childId = parcel.readLong();
+                mChildNodeIds.add(childId);
+            }
         }
 
         mBoundsInParent.top = parcel.readInt();
@@ -2331,7 +2445,9 @@
         mWindowId = UNDEFINED;
         mConnectionId = UNDEFINED;
         mMovementGranularities = 0;
-        mChildNodeIds.clear();
+        if (mChildNodeIds != null) {
+            mChildNodeIds.clear();
+        }
         mBoundsInParent.set(0, 0, 0, 0);
         mBoundsInScreen.set(0, 0, 0, 0);
         mBooleanProperties = 0;
@@ -2493,12 +2609,14 @@
             }
             builder.append("]");
 
-            SparseLongArray childIds = mChildNodeIds;
             builder.append("; childAccessibilityIds: [");
-            for (int i = 0, count = childIds.size(); i < count; i++) {
-                builder.append(childIds.valueAt(i));
-                if (i < count - 1) {
-                    builder.append(", ");
+            final LongArray childIds = mChildNodeIds;
+            if (childIds != null) {
+                for (int i = 0, count = childIds.size(); i < count; i++) {
+                    builder.append(childIds.get(i));
+                    if (i < count - 1) {
+                        builder.append(", ");
+                    }
                 }
             }
             builder.append("]");
@@ -2893,16 +3011,18 @@
     }
 
     /**
-     * @see Parcelable.Creator
+     * @see android.os.Parcelable.Creator
      */
     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
             new Parcelable.Creator<AccessibilityNodeInfo>() {
+        @Override
         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
             AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
             info.initFromParcel(parcel);
             return info;
         }
 
+        @Override
         public AccessibilityNodeInfo[] newArray(int size) {
             return new AccessibilityNodeInfo[size];
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index a9473a8..85aca61 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -18,6 +18,7 @@
 
 import android.os.Build;
 import android.util.Log;
+import android.util.LongArray;
 import android.util.LongSparseArray;
 import android.util.SparseLongArray;
 
@@ -172,12 +173,12 @@
                     // the new one represents a source state where some of the
                     // children have been removed to avoid having disconnected
                     // subtrees in the cache.
-                    SparseLongArray oldChildrenIds = oldInfo.getChildNodeIds();
-                    SparseLongArray newChildrenIds = info.getChildNodeIds();
-                    final int oldChildCount = oldChildrenIds.size();
+                    // TODO: Runs in O(n^2), could optimize to O(n + n log n)
+                    final LongArray newChildrenIds = info.getChildNodeIds();
+                    final int oldChildCount = oldInfo.getChildCount();
                     for (int i = 0; i < oldChildCount; i++) {
-                        final long oldChildId = oldChildrenIds.valueAt(i);
-                        if (newChildrenIds.indexOfValue(oldChildId) < 0) {
+                        final long oldChildId = oldInfo.getChildId(i);
+                        if (newChildrenIds.indexOf(oldChildId) < 0) {
                             clearSubTreeLocked(oldChildId);
                         }
                     }
@@ -237,10 +238,9 @@
             return;
         }
         mCacheImpl.remove(rootNodeId);
-        SparseLongArray childNodeIds = current.getChildNodeIds();
-        final int childCount = childNodeIds.size();
+        final int childCount = current.getChildCount();
         for (int i = 0; i < childCount; i++) {
-            final long childNodeId = childNodeIds.valueAt(i);
+            final long childNodeId = current.getChildId(i);
             clearSubTreeRecursiveLocked(childNodeId);
         }
     }
@@ -301,11 +301,10 @@
                     }
                 }
 
-                SparseLongArray childIds = current.getChildNodeIds();
-                final int childCount = childIds.size();
+                final int childCount = current.getChildCount();
                 for (int i = 0; i < childCount; i++) {
-                    final long childId = childIds.valueAt(i);
-                    AccessibilityNodeInfo child = mCacheImpl.get(childId);
+                    final long childId = current.getChildId(i);
+                    final AccessibilityNodeInfo child = mCacheImpl.get(childId);
                     if (child != null) {
                         fringe.add(child);
                     }
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 84072bf06..e7ada27 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/Editor.java b/core/java/android/widget/Editor.java
index aa3a25d..0e4d422 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1346,7 +1346,7 @@
                 DisplayList blockDisplayList = mTextDisplayLists[blockIndex];
                 if (blockDisplayList == null) {
                     blockDisplayList = mTextDisplayLists[blockIndex] =
-                            mTextView.getHardwareRenderer().createDisplayList("Text " + blockIndex);
+                            DisplayList.create("Text " + blockIndex);
                 } else {
                     if (blockIsInvalid) blockDisplayList.clear();
                 }
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index cfd7e4a..79d5e5d 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -715,6 +715,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/TextView.java b/core/java/android/widget/TextView.java
index d28be7b..fca62df 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -56,6 +56,7 @@
 import android.text.SpanWatcher;
 import android.text.Spannable;
 import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.SpannedString;
 import android.text.StaticLayout;
@@ -3498,19 +3499,7 @@
             ss.selEnd = end;
 
             if (mText instanceof Spanned) {
-                /*
-                 * Calling setText() strips off any ChangeWatchers;
-                 * strip them now to avoid leaking references.
-                 * But do it to a copy so that if there are any
-                 * further changes to the text of this view, it
-                 * won't get into an inconsistent state.
-                 */
-
-                Spannable sp = new SpannableString(mText);
-
-                for (ChangeWatcher cw : sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
-                    sp.removeSpan(cw);
-                }
+                Spannable sp = new SpannableStringBuilder(mText);
 
                 if (mEditor != null) {
                     removeMisspelledSpans(sp);
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index bb4116a..f23c64f 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -55,7 +55,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 2363062..0771329 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -66,6 +66,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 a3aee05..2e5fcec 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -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>();
@@ -2172,6 +2174,9 @@
                 case TelephonyManager.NETWORK_TYPE_EHRPD:
                     bin = DATA_CONNECTION_EHRPD;
                     break;
+                case TelephonyManager.NETWORK_TYPE_HSPAP:
+                    bin = DATA_CONNECTION_HSPAP;
+                    break;
                 default:
                     bin = DATA_CONNECTION_OTHER;
                     break;
@@ -2401,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) {
@@ -2453,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++) {
@@ -2576,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;
 
@@ -2626,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);
         }
@@ -2716,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;
@@ -2851,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;
@@ -2911,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++) {
@@ -2971,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;
@@ -3077,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();
                 }
@@ -3154,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);
@@ -3263,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,
@@ -5460,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);
@@ -5671,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);
@@ -5906,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/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 69b593a..5538dca 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -104,18 +104,6 @@
         Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
 
         /*
-         * In case the runtime switched since last boot (such as when
-         * the old runtime was removed in an OTA), set the system
-         * property so that it is in sync. We can't do this in
-         * libnativehelper's JniInvocation::Init code where we already
-         * had to fallback to a different runtime because it is
-         * running as root and we need to be the system user to set
-         * the property. http://b/11463182
-         */
-        SystemProperties.set("persist.sys.dalvik.vm.lib",
-                             VMRuntime.getRuntime().vmLibrary());
-
-        /*
          * Install a TimezoneGetter subclass for ZoneInfo.db
          */
         TimezoneGetter.setInstance(new TimezoneGetter() {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 3381959..4f3b5b3 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -197,10 +197,14 @@
 
         try {
             parsedArgs = new Arguments(args);
+            if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
+                throw new ZygoteSecurityException("Client may not specify capabilities: " +
+                        "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
+                        ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
+            }
 
             applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
             applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
             applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
             applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
 
@@ -703,71 +707,6 @@
     }
 
     /**
-     * Applies zygote security policy per bug #1042973. A root peer may
-     * spawn an instance with any capabilities. All other uids may spawn
-     * instances with any of the capabilities in the peer's permitted set
-     * but no more.
-     *
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyCapabilitiesSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-
-        if (args.permittedCapabilities == 0
-                && args.effectiveCapabilities == 0) {
-            // nothing to check
-            return;
-        }
-
-        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                     peerSecurityContext,
-                                                     "zygote",
-                                                     "specifycapabilities");
-        if (!allowed) {
-            throw new ZygoteSecurityException(
-                    "Peer may not specify capabilities");
-        }
-
-        if (peer.getUid() == 0) {
-            // root may specify anything
-            return;
-        }
-
-        long permittedCaps;
-
-        try {
-            permittedCaps = ZygoteInit.capgetPermitted(peer.getPid());
-        } catch (IOException ex) {
-            throw new ZygoteSecurityException(
-                    "Error retrieving peer's capabilities.");
-        }
-
-        /*
-         * Ensure that the client did not specify an effective set larger
-         * than the permitted set. The kernel will enforce this too, but we
-         * do it here to make the following check easier.
-         */
-        if (((~args.permittedCapabilities) & args.effectiveCapabilities) != 0) {
-            throw new ZygoteSecurityException(
-                    "Effective capabilities cannot be superset of "
-                            + " permitted capabilities" );
-        }
-
-        /*
-         * Ensure that the new permitted (and thus the new effective) set is
-         * a subset of the peer process's permitted set
-         */
-
-        if (((~permittedCaps) & args.permittedCapabilities) != 0) {
-            throw new ZygoteSecurityException(
-                    "Peer specified unpermitted capabilities" );
-        }
-    }
-
-    /**
      * Applies zygote security policy.
      * Based on the credentials of the process issuing a zygote command:
      * <ol>
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index c37cac5..48092f6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -301,6 +301,8 @@
                         count++;
                     } catch (ClassNotFoundException e) {
                         Log.w(TAG, "Class not found for preloading: " + line);
+                    } catch (UnsatisfiedLinkError e) {
+                        Log.w(TAG, "Problem preloading " + line + ": " + e);
                     } catch (Throwable t) {
                         Log.e(TAG, "Error preloading " + line + ".", t);
                         if (t instanceof Error) {
@@ -721,15 +723,6 @@
             throws IOException;
 
     /**
-     * Retrieves the permitted capability set from another process.
-     *
-     * @param pid &gt;=0 process ID or 0 for this process
-     * @throws IOException on error
-     */
-    static native long capgetPermitted(int pid)
-            throws IOException;
-
-    /**
      * Invokes select() on the provider array of file descriptors (selecting
      * for readability only). Array elements of null are ignored.
      *
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 1a57e4e..0000000
--- a/core/java/com/android/internal/view/CheckableLinearLayout.java
+++ /dev/null
@@ -1,71 +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 defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-        // TODO Auto-generated constructor stub
-    }
-
-    public CheckableLinearLayout(
-            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        // 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/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 44e7ec1..4654178 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -721,7 +721,8 @@
             if (subMenu == null) return false;
 
             mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
-            return false;
+            final MenuPresenter.Callback cb = getCallback();
+            return cb != null ? cb.onOpenSubMenu(subMenu) : false;
         }
 
         @Override
@@ -729,6 +730,10 @@
             if (menu instanceof SubMenuBuilder) {
                 ((SubMenuBuilder) menu).getRootMenu().close(false);
             }
+            final MenuPresenter.Callback cb = getCallback();
+            if (cb != null) {
+                cb.onCloseMenu(menu, allMenusAreClosing);
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
index db0d6dd..92e9ea6 100644
--- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
@@ -144,6 +144,10 @@
         mCallback = cb;
     }
 
+    public Callback getCallback() {
+        return mCallback;
+    }
+
     /**
      * Create a new item view that can be re-bound to other item data later.
      *
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index b5d74e8..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) {
@@ -566,7 +566,11 @@
         mUpGoerFive.setEnabled(enable);
         mUpGoerFive.setFocusable(enable);
         // Make sure the home button has an accurate content description for accessibility.
-        if (!enable) {
+        updateHomeAccessibility(enable);
+    }
+
+    private void updateHomeAccessibility(boolean homeEnabled) {
+        if (!homeEnabled) {
             mUpGoerFive.setContentDescription(null);
             mUpGoerFive.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         } else {
@@ -677,19 +681,7 @@
         }
 
         // Make sure the home button has an accurate content description for accessibility.
-        if (!mHomeLayout.isEnabled()) {
-            mHomeLayout.setContentDescription(null);
-            mHomeLayout.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
-        } else {
-            mHomeLayout.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_AUTO);
-            if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
-                mHomeLayout.setContentDescription(mContext.getResources().getText(
-                        R.string.action_bar_up_description));
-            } else {
-                mHomeLayout.setContentDescription(mContext.getResources().getText(
-                        R.string.action_bar_home_description));
-            }
-        }
+        updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
     public void setIcon(Drawable icon) {
@@ -1340,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/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index d82831f..e339c44 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -31,11 +31,13 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.MotionEvent.PointerCoords;
 
 import java.util.ArrayList;
 
-public class PointerLocationView extends View implements InputDeviceListener {
+public class PointerLocationView extends View implements InputDeviceListener,
+        PointerEventListener {
     private static final String TAG = "Pointer";
 
     // The system property key used to specify an alternate velocity tracker strategy
@@ -520,7 +522,8 @@
                 .toString());
     }
 
-    public void addPointerEvent(MotionEvent event) {
+    @Override
+    public void onPointerEvent(MotionEvent event) {
         final int action = event.getAction();
         int NP = mPointers.size();
 
@@ -648,7 +651,7 @@
     
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        addPointerEvent(event);
+        onPointerEvent(event);
 
         if (event.getAction() == MotionEvent.ACTION_DOWN && !isFocused()) {
             requestFocus();
@@ -660,7 +663,7 @@
     public boolean onGenericMotionEvent(MotionEvent event) {
         final int source = event.getSource();
         if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
-            addPointerEvent(event);
+            onPointerEvent(event);
         } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
             logMotionEvent("Joystick", event);
         } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 5983120..04661d7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -4,6 +4,7 @@
 LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
 LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
 LOCAL_CFLAGS += -U__APPLE__
+LOCAL_CFLAGS += -Wno-unused-parameter
 
 ifeq ($(TARGET_ARCH), arm)
 	LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
@@ -50,8 +51,8 @@
 	android_view_InputQueue.cpp \
 	android_view_KeyEvent.cpp \
 	android_view_KeyCharacterMap.cpp \
-	android_view_HardwareRenderer.cpp \
 	android_view_GraphicBuffer.cpp \
+	android_view_GLRenderer.cpp \
 	android_view_GLES20DisplayList.cpp \
 	android_view_GLES20Canvas.cpp \
 	android_view_MotionEvent.cpp \
@@ -114,6 +115,7 @@
 	android/graphics/TextLayout.cpp \
 	android/graphics/TextLayoutCache.cpp \
 	android/graphics/Typeface.cpp \
+	android/graphics/TypefaceImpl.cpp \
 	android/graphics/Utils.cpp \
 	android/graphics/Xfermode.cpp \
 	android/graphics/YuvToJpegEncoder.cpp \
@@ -216,6 +218,16 @@
 	LOCAL_SHARED_LIBRARIES += libhwui
 endif
 
+ifeq ($(USE_MINIKIN), true)
+	LOCAL_CFLAGS += -DUSE_MINIKIN
+	LOCAL_C_INCLUDES += frameworks/minikin/include \
+		external/freetype/include
+	LOCAL_SRC_FILES += 	android/graphics/MinikinSkia.cpp
+# note: the freetype include is spurious; minikin itself probably
+# shouldn't depend on it
+	LOCAL_SHARED_LIBRARIES += libminikin libstlport
+endif
+
 LOCAL_SHARED_LIBRARIES += \
 	libdl
 # we need to access the private Bionic header
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 1cce263..d501dd8 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -122,7 +122,7 @@
 extern int register_android_view_GraphicBuffer(JNIEnv* env);
 extern int register_android_view_GLES20DisplayList(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
-extern int register_android_view_HardwareRenderer(JNIEnv* env);
+extern int register_android_view_GLRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
@@ -1118,7 +1118,7 @@
     REG_JNI(register_android_view_GraphicBuffer),
     REG_JNI(register_android_view_GLES20DisplayList),
     REG_JNI(register_android_view_GLES20Canvas),
-    REG_JNI(register_android_view_HardwareRenderer),
+    REG_JNI(register_android_view_GLRenderer),
     REG_JNI(register_android_view_Surface),
     REG_JNI(register_android_view_SurfaceControl),
     REG_JNI(register_android_view_SurfaceSession),
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 813dd5a..9a00d538 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -27,8 +27,14 @@
 #include "SkShader.h"
 #include "SkTemplates.h"
 
+#ifdef USE_MINIKIN
+#include <minikin/Layout.h>
+#include "MinikinSkia.h"
+#endif
+
 #include "TextLayout.h"
 #include "TextLayoutCache.h"
+#include "TypefaceImpl.h"
 
 #include "unicode/ubidi.h"
 #include "unicode/ushape.h"
@@ -742,35 +748,83 @@
     }
 
 
-    static void drawText___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+    static void drawText___CIIFFIPaintTypeface(JNIEnv* env, jobject, SkCanvas* canvas,
                                       jcharArray text, int index, int count,
-                                      jfloat x, jfloat y, int flags, SkPaint* paint) {
+                                      jfloat x, jfloat y, int flags, SkPaint* paint,
+                                      TypefaceImpl *typeface) {
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint, typeface);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
     }
 
-    static void drawText__StringIIFFIPaint(JNIEnv* env, jobject,
+    static void drawText__StringIIFFIPaintTypeface(JNIEnv* env, jobject,
                                           SkCanvas* canvas, jstring text,
                                           int start, int end,
-                                          jfloat x, jfloat y, int flags, SkPaint* paint) {
+                                          jfloat x, jfloat y, int flags, SkPaint* paint,
+                                          TypefaceImpl *typeface) {
         const jchar* textArray = env->GetStringChars(text, NULL);
-        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint, typeface);
         env->ReleaseStringChars(text, textArray);
     }
 
+#ifdef USE_MINIKIN
+    static void drawGlyphsToSkia(SkCanvas *canvas, SkPaint *paint, Layout *layout, float x, float y) {
+        size_t nGlyphs = layout->nGlyphs();
+        uint16_t *glyphs = new uint16_t[nGlyphs];
+        SkPoint *pos = new SkPoint[nGlyphs];
+        SkTypeface *lastFace = NULL;
+        SkTypeface *skFace = NULL;
+        size_t start = 0;
+
+        paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+        for (size_t i = 0; i < nGlyphs; i++) {
+            MinikinFontSkia *mfs = static_cast<MinikinFontSkia *>(layout->getFont(i));
+            skFace = mfs->GetSkTypeface();
+            glyphs[i] = layout->getGlyphId(i);
+            pos[i].fX = SkFloatToScalar(x + layout->getX(i));
+            pos[i].fY = SkFloatToScalar(y + layout->getY(i));
+            if (i > 0 && skFace != lastFace) {
+                paint->setTypeface(lastFace);
+                canvas->drawPosText(glyphs + start, (i - start) << 1, pos + start, *paint);
+                start = i;
+            }
+            lastFace = skFace;
+        }
+        if (skFace != NULL) {
+            paint->setTypeface(skFace);
+            canvas->drawPosText(glyphs + start, (nGlyphs - start) << 1, pos + start, *paint);
+        }
+        delete[] glyphs;
+        delete[] pos;
+    }
+#endif
+
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int end,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
 
         jint count = end - start;
-        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint);
+        drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint, typeface);
     }
 
     static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
             int start, int count, int contextCount,
-            jfloat x, jfloat y, int flags, SkPaint* paint) {
+            jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) {
 
+#ifdef USE_MINIKIN
+        Layout layout;
+        TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
+        layout.setFontCollection(resolvedFace->fFontCollection);
+        FontStyle style = resolvedFace->fStyle;
+        char css[256];
+        sprintf(css, "font-size: %d; font-weight: %d; font-style: %s",
+            (int)paint->getTextSize(),
+            style.getWeight() * 100,
+            style.getItalic() ? "italic" : "normal");
+        layout.setProperties(css);
+        layout.doLayout(textArray + start, count);
+        drawGlyphsToSkia(canvas, paint, &layout, x, y);
+#else
         sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
                 textArray, start, count, contextCount, flags);
         if (value == NULL) {
@@ -786,6 +840,7 @@
         doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint);
         doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint);
         paint->setTextAlign(align);
+#endif
     }
 
 // Same values used by Skia
@@ -842,27 +897,29 @@
         delete[] posPtr;
     }
 
-    static void drawTextRun___CIIIIFFIPaint(
+    static void drawTextRun___CIIIIFFIPaintTypeface(
         JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
         int count, int contextIndex, int contextCount,
-        jfloat x, jfloat y, int dirFlags, SkPaint* paint) {
+        jfloat x, jfloat y, int dirFlags, SkPaint* paint,
+        TypefaceImpl* typeface) {
 
         jchar* chars = env->GetCharArrayElements(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex,
-                count, contextCount, x, y, dirFlags, paint);
+                count, contextCount, x, y, dirFlags, paint, typeface);
         env->ReleaseCharArrayElements(text, chars, JNI_ABORT);
     }
 
-    static void drawTextRun__StringIIIIFFIPaint(
+    static void drawTextRun__StringIIIIFFIPaintTypeface(
         JNIEnv* env, jobject obj, SkCanvas* canvas, jstring text, jint start,
         jint end, jint contextStart, jint contextEnd,
-        jfloat x, jfloat y, jint dirFlags, SkPaint* paint) {
+        jfloat x, jfloat y, jint dirFlags, SkPaint* paint,
+        TypefaceImpl* typeface) {
 
         jint count = end - start;
         jint contextCount = contextEnd - contextStart;
         const jchar* chars = env->GetStringChars(text, NULL);
         drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart,
-                count, contextCount, x, y, dirFlags, paint);
+                count, contextCount, x, y, dirFlags, paint, typeface);
         env->ReleaseStringChars(text, chars);
     }
 
@@ -1070,14 +1127,14 @@
         (void*)SkCanvasGlue::drawBitmapMesh},
     {"nativeDrawVertices", "(III[FI[FI[II[SIII)V",
         (void*)SkCanvasGlue::drawVertices},
-    {"native_drawText","(I[CIIFFII)V",
-        (void*) SkCanvasGlue::drawText___CIIFFIPaint},
-    {"native_drawText","(ILjava/lang/String;IIFFII)V",
-        (void*) SkCanvasGlue::drawText__StringIIFFIPaint},
-    {"native_drawTextRun","(I[CIIIIFFII)V",
-        (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
-    {"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
-        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaint},
+    {"native_drawText","(I[CIIFFIII)V",
+        (void*) SkCanvasGlue::drawText___CIIFFIPaintTypeface},
+    {"native_drawText","(ILjava/lang/String;IIFFIII)V",
+        (void*) SkCanvasGlue::drawText__StringIIFFIPaintTypeface},
+    {"native_drawTextRun","(I[CIIIIFFIII)V",
+        (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaintTypeface},
+    {"native_drawTextRun","(ILjava/lang/String;IIIIFFIII)V",
+        (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaintTypeface},
     {"native_drawPosText","(I[CII[FI)V",
         (void*) SkCanvasGlue::drawPosText___CII_FPaint},
     {"native_drawPosText","(ILjava/lang/String;[FI)V",
diff --git a/core/jni/android/graphics/MinikinSkia.cpp b/core/jni/android/graphics/MinikinSkia.cpp
new file mode 100644
index 0000000..622c935
--- /dev/null
+++ b/core/jni/android/graphics/MinikinSkia.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include <SkTypeface.h>
+#include <SkPaint.h>
+#include <SkFP.h>
+
+#define LOG_TAG "Minikin"
+#include <cutils/log.h>
+
+#include <minikin/MinikinFont.h>
+#include "MinikinSkia.h"
+
+namespace android {
+
+MinikinFontSkia::MinikinFontSkia(SkTypeface *typeface) :
+    mTypeface(typeface) {
+}
+
+MinikinFontSkia::~MinikinFontSkia() {
+    SkSafeUnref(mTypeface);
+}
+
+bool MinikinFontSkia::GetGlyph(uint32_t codepoint, uint32_t *glyph) const {
+    SkPaint paint;
+    paint.setTypeface(mTypeface);
+    paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
+    uint16_t glyph16;
+    paint.textToGlyphs(&codepoint, sizeof(codepoint), &glyph16);
+    *glyph  = glyph16;
+    return !!glyph;
+}
+
+float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
+    const MinikinPaint &paint) const {
+    SkPaint skpaint;
+    skpaint.setTypeface(mTypeface);
+    skpaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    // TODO: set more paint parameters from Minikin
+    skpaint.setTextSize(paint.size);
+    uint16_t glyph16 = glyph_id;
+    SkScalar skWidth;
+    SkRect skBounds;
+    skpaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, &skBounds);
+    // TODO: get bounds information
+    return SkScalarToFP(skWidth);
+}
+
+bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) {
+    if (buf == NULL) {
+        const size_t tableSize = mTypeface->getTableSize(tag);
+        *size = tableSize;
+        return tableSize != 0;
+    } else {
+        const size_t actualSize = mTypeface->getTableData(tag, 0, *size, buf);
+        *size = actualSize;
+        return actualSize != 0;
+    }
+}
+
+SkTypeface *MinikinFontSkia::GetSkTypeface() {
+    return mTypeface;
+}
+
+int32_t MinikinFontSkia::GetUniqueId() const {
+    return mTypeface->uniqueID();
+}
+
+}
diff --git a/core/jni/android/graphics/MinikinSkia.h b/core/jni/android/graphics/MinikinSkia.h
new file mode 100644
index 0000000..0edb557
--- /dev/null
+++ b/core/jni/android/graphics/MinikinSkia.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+namespace android {
+
+class MinikinFontSkia : public MinikinFont {
+public:
+    explicit MinikinFontSkia(SkTypeface *typeface);
+
+    ~MinikinFontSkia();
+
+    bool GetGlyph(uint32_t codepoint, uint32_t *glyph) const;
+
+    float GetHorizontalAdvance(uint32_t glyph_id,
+        const MinikinPaint &paint) const;
+
+    // If buf is NULL, just update size
+    bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
+
+    int32_t GetUniqueId() const;
+
+    SkTypeface *GetSkTypeface();
+
+private:
+    SkTypeface *mTypeface;
+
+};
+
+}  // namespace android
\ No newline at end of file
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 40e0731..1ca3f3a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -245,7 +245,12 @@
     }
 
     static SkTypeface* setTypeface(JNIEnv* env, jobject clazz, SkPaint* obj, SkTypeface* typeface) {
+#ifndef USE_MINIKIN
         return obj->setTypeface(typeface);
+#else
+        // TODO(raph): not yet implemented
+        return NULL;
+#endif
     }
 
     static SkRasterizer* setRasterizer(JNIEnv* env, jobject clazz, SkPaint* obj, SkRasterizer* rasterizer) {
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index a7a0bb2..04f9fe1 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -1,9 +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.
+ */
+
 #include "jni.h"
 #include <android_runtime/AndroidRuntime.h>
 
 #include "GraphicsJNI.h"
 #include "SkStream.h"
 #include "SkTypeface.h"
+#include "TypefaceImpl.h"
 #include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/AssetManager.h>
 
@@ -27,100 +44,46 @@
     const char* fCStr;
 };
 
-static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name,
+static TypefaceImpl* Typeface_create(JNIEnv* env, jobject, jstring name,
                                    SkTypeface::Style style) {
-    SkTypeface* face = NULL;
+    TypefaceImpl* face = NULL;
 
     if (NULL != name) {
         AutoJavaStringToUTF8    str(env, name);
-        face = SkTypeface::CreateFromName(str.c_str(), style);
+        face = TypefaceImpl_createFromName(str.c_str(), style);
     }
 
     // return the default font at the best style if no exact match exists
     if (NULL == face) {
-        face = SkTypeface::CreateFromName(NULL, style);
+        face = TypefaceImpl_createFromName(NULL, style);
     }
     return face;
 }
 
-static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* family, int style) {
-    SkTypeface* face = SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
-    // return the default font at the best style if the requested style does not
-    // exist in the provided family
+static TypefaceImpl* Typeface_createFromTypeface(JNIEnv* env, jobject, TypefaceImpl* family, int style) {
+    TypefaceImpl* face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)style);
+    // Try to find the closest matching font, using the standard heuristic
     if (NULL == face) {
-        face = SkTypeface::CreateFromName(NULL, (SkTypeface::Style)style);
+        face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
+    }
+    for (int i = 0; NULL == face && i < 4; i++) {
+        face = TypefaceImpl_createFromTypeface(family, (SkTypeface::Style)i);
+    }
+    if (NULL == face) {
+        face = TypefaceImpl_createFromName(NULL, (SkTypeface::Style)style);
     }
     return face;
 }
 
-static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
-    SkSafeUnref(face);
+static void Typeface_unref(JNIEnv* env, jobject obj, TypefaceImpl* face) {
+    TypefaceImpl_unref(face);
 }
 
-static int Typeface_getStyle(JNIEnv* env, jobject obj, SkTypeface* face) {
-    return face->style();
+static int Typeface_getStyle(JNIEnv* env, jobject obj, TypefaceImpl* face) {
+    return TypefaceImpl_getStyle(face);
 }
 
-class AssetStream : public SkStream {
-public:
-    AssetStream(Asset* asset, bool hasMemoryBase) : fAsset(asset)
-    {
-        fMemoryBase = hasMemoryBase ? fAsset->getBuffer(false) : NULL;
-    }
-
-    virtual ~AssetStream()
-    {
-        delete fAsset;
-    }
-
-    virtual const void* getMemoryBase()
-    {
-        return fMemoryBase;
-    }
-
-	virtual bool rewind()
-    {
-        off64_t pos = fAsset->seek(0, SEEK_SET);
-        return pos != (off64_t)-1;
-    }
-
-	virtual size_t read(void* buffer, size_t size)
-    {
-        ssize_t amount;
-
-        if (NULL == buffer)
-        {
-            if (0 == size)  // caller is asking us for our total length
-                return fAsset->getLength();
-
-            // asset->seek returns new total offset
-            // we want to return amount that was skipped
-
-            off64_t oldOffset = fAsset->seek(0, SEEK_CUR);
-            if (-1 == oldOffset)
-                return 0;
-            off64_t newOffset = fAsset->seek(size, SEEK_CUR);
-            if (-1 == newOffset)
-                return 0;
-
-            amount = newOffset - oldOffset;
-        }
-        else
-        {
-            amount = fAsset->read(buffer, size);
-        }
-
-        if (amount < 0)
-            amount = 0;
-        return amount;
-    }
-
-private:
-    Asset*      fAsset;
-    const void* fMemoryBase;
-};
-
-static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject,
+static TypefaceImpl* Typeface_createFromAsset(JNIEnv* env, jobject,
                                             jobject jassetMgr,
                                             jstring jpath) {
 
@@ -138,21 +101,15 @@
         return NULL;
     }
 
-    SkStream* stream = new AssetStream(asset, true);
-    SkTypeface* face = SkTypeface::CreateFromStream(stream);
-    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
-    // need to unref it here or it won't be freed later on
-    stream->unref();
-
-    return face;
+    return TypefaceImpl_createFromAsset(asset);
 }
 
-static SkTypeface* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
+static TypefaceImpl* Typeface_createFromFile(JNIEnv* env, jobject, jstring jpath) {
     NPE_CHECK_RETURN_ZERO(env, jpath);
 
     AutoJavaStringToUTF8 str(env, jpath);
 
-    return SkTypeface::CreateFromFile(str.c_str());
+    return TypefaceImpl_createFromFile(str.c_str());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/TypefaceImpl.cpp b/core/jni/android/graphics/TypefaceImpl.cpp
new file mode 100644
index 0000000..8874db8
--- /dev/null
+++ b/core/jni/android/graphics/TypefaceImpl.cpp
@@ -0,0 +1,256 @@
+/*
+ * 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.
+ */
+
+/**
+ * This is the implementation of the Typeface object. Historically, it has
+ * just been SkTypeface, but we are migrating to Minikin. For the time
+ * being, that choice is hidden under the USE_MINIKIN compile-time flag.
+ */
+
+#include "SkStream.h"
+#include "SkTypeface.h"
+
+#ifdef USE_MINIKIN
+#include <vector>
+#include <minikin/FontCollection.h>
+#include <minikin/FontFamily.h>
+#include <minikin/Layout.h>
+#include "MinikinSkia.h"
+#endif
+
+#include "TypefaceImpl.h"
+
+namespace android {
+
+class AssetStream : public SkStream {
+public:
+    AssetStream(Asset* asset, bool hasMemoryBase) : fAsset(asset)
+    {
+        fMemoryBase = hasMemoryBase ? fAsset->getBuffer(false) : NULL;
+    }
+
+    virtual ~AssetStream()
+    {
+        delete fAsset;
+    }
+
+    virtual const void* getMemoryBase()
+    {
+        return fMemoryBase;
+    }
+
+    virtual bool rewind()
+    {
+        off64_t pos = fAsset->seek(0, SEEK_SET);
+        return pos != (off64_t)-1;
+    }
+
+    virtual size_t read(void* buffer, size_t size)
+    {
+        ssize_t amount;
+
+        if (NULL == buffer)
+        {
+            if (0 == size)  // caller is asking us for our total length
+                return fAsset->getLength();
+
+            // asset->seek returns new total offset
+            // we want to return amount that was skipped
+
+            off64_t oldOffset = fAsset->seek(0, SEEK_CUR);
+            if (-1 == oldOffset)
+                return 0;
+            off64_t newOffset = fAsset->seek(size, SEEK_CUR);
+            if (-1 == newOffset)
+                return 0;
+
+            amount = newOffset - oldOffset;
+        }
+        else
+        {
+            amount = fAsset->read(buffer, size);
+        }
+
+        if (amount < 0)
+            amount = 0;
+        return amount;
+    }
+
+private:
+    Asset*      fAsset;
+    const void* fMemoryBase;
+};
+
+#ifdef USE_MINIKIN
+
+// Any weight greater than or equal to this is considered "bold" for
+// legacy API.
+static const int kBoldThreshold = 6;
+
+static FontStyle styleFromSkiaStyle(SkTypeface::Style skiaStyle) {
+    int weight = (skiaStyle & SkTypeface::kBold) != 0 ? 7 : 4;
+    bool italic = (skiaStyle & SkTypeface::kItalic) != 0;
+    return FontStyle(weight, italic);
+}
+
+TypefaceImpl* gDefaultTypeface;
+pthread_once_t gDefaultTypefaceOnce = PTHREAD_ONCE_INIT;
+
+// TODO: this currently builds a font collection from hardcoded paths.
+// It will get replaced by an implementation that parses the XML files.
+static FontCollection *makeFontCollection() {
+    std::vector<FontFamily *>typefaces;
+    const char *fns[] = {
+        "/system/fonts/Roboto-Regular.ttf",
+        "/system/fonts/Roboto-Italic.ttf",
+        "/system/fonts/Roboto-BoldItalic.ttf",
+        "/system/fonts/Roboto-Light.ttf",
+        "/system/fonts/Roboto-Thin.ttf",
+        "/system/fonts/Roboto-Bold.ttf",
+        "/system/fonts/Roboto-ThinItalic.ttf",
+        "/system/fonts/Roboto-LightItalic.ttf"
+    };
+
+    FontFamily *family = new FontFamily();
+    for (size_t i = 0; i < sizeof(fns)/sizeof(fns[0]); i++) {
+        const char *fn = fns[i];
+        SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
+        MinikinFont *font = new MinikinFontSkia(skFace);
+        family->addFont(font);
+    }
+    typefaces.push_back(family);
+
+    family = new FontFamily();
+    const char *fn = "/system/fonts/NotoSansDevanagari-Regular.ttf";
+    SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
+    MinikinFont *font = new MinikinFontSkia(skFace);
+    family->addFont(font);
+    typefaces.push_back(family);
+
+    return new FontCollection(typefaces);
+}
+
+static void getDefaultTypefaceOnce() {
+    Layout::init();
+    gDefaultTypeface = new TypefaceImpl;
+    gDefaultTypeface->fFontCollection = makeFontCollection();
+    gDefaultTypeface->fStyle = FontStyle();
+}
+
+TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src) {
+    if (src == NULL) {
+        pthread_once(&gDefaultTypefaceOnce, getDefaultTypefaceOnce);
+        return gDefaultTypeface;
+    } else {
+        return src;
+    }
+}
+
+TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
+    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(src);
+    TypefaceImpl* result = new TypefaceImpl;
+    if (result != 0) {
+        result->fFontCollection = resolvedFace->fFontCollection;
+        result->fStyle = styleFromSkiaStyle(style);
+    }
+    return result;
+}
+
+static TypefaceImpl* createFromSkTypeface(SkTypeface* typeface) {
+    MinikinFont* minikinFont = new MinikinFontSkia(typeface);
+    std::vector<FontFamily *> typefaces;
+    FontFamily* family = new FontFamily();
+    family->addFont(minikinFont);
+    typefaces.push_back(family);
+    TypefaceImpl* result = new TypefaceImpl;
+    result->fFontCollection = new FontCollection(typefaces);
+    result->fStyle = FontStyle();  // TODO: improve
+    return result;
+}
+
+TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
+    // TODO: should create a font collection with all styles corresponding to
+    // the name
+    SkTypeface* face = SkTypeface::CreateFromName(name, style);
+    return createFromSkTypeface(face);
+}
+
+TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
+    SkTypeface* face = SkTypeface::CreateFromFile(filename);
+    return createFromSkTypeface(face);
+}
+
+TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
+    SkStream* stream = new AssetStream(asset, true);
+    SkTypeface* face = SkTypeface::CreateFromStream(stream);
+    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
+    // need to unref it here or it won't be freed later on
+    stream->unref();
+    return createFromSkTypeface(face);
+}
+
+void TypefaceImpl_unref(TypefaceImpl* face) {
+    delete face;
+}
+
+int TypefaceImpl_getStyle(TypefaceImpl* face) {
+    FontStyle style = face->fStyle;
+    int result = style.getItalic() ? SkTypeface::kItalic : 0;
+    if (style.getWeight() >= kBoldThreshold) {
+        result |= SkTypeface::kBold;
+    }
+    return result;
+}
+
+#else  // USE_MINIKIN
+
+/* Just use SkTypeface instead. */
+
+typedef SkTypeface TypefaceImpl;
+
+TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style) {
+    return SkTypeface::CreateFromTypeface(src, style);
+}
+
+TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style) {
+    return SkTypeface::CreateFromName(name, style);
+}
+
+TypefaceImpl* TypefaceImpl_createFromFile(const char* filename) {
+    return SkTypeface::CreateFromFile(filename);
+}
+
+TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset) {
+    SkStream* stream = new AssetStream(asset, true);
+    SkTypeface* face = SkTypeface::CreateFromStream(stream);
+    // SkTypeFace::CreateFromStream calls ref() on the stream, so we
+    // need to unref it here or it won't be freed later on
+    stream->unref();
+
+    return face;
+}
+
+void TypefaceImpl_unref(TypefaceImpl* face) {
+    SkSafeUnref(face);
+}
+
+int TypefaceImpl_getStyle(TypefaceImpl* face) {
+    return face->style();
+}
+
+#endif  // USE_MINIKIN
+
+}
diff --git a/core/jni/android/graphics/TypefaceImpl.h b/core/jni/android/graphics/TypefaceImpl.h
new file mode 100644
index 0000000..4c51bec
--- /dev/null
+++ b/core/jni/android/graphics/TypefaceImpl.h
@@ -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.
+ */
+
+
+#ifndef ANDROID_TYPEFACE_IMPL_H
+#define ANDROID_TYPEFACE_IMPL_H
+
+#include <androidfw/AssetManager.h>
+
+#ifdef USE_MINIKIN
+#include <minikin/FontCollection.h>
+#endif
+
+namespace android {
+
+#ifdef USE_MINIKIN
+struct TypefaceImpl {
+    FontCollection *fFontCollection;
+    FontStyle fStyle;
+};
+
+// Note: it would be cleaner if the following functions were member
+// functions (static or otherwise) of the TypefaceImpl class. However,
+// that can't be easily accommodated in the case where TypefaceImpl
+// is just a pointer to SkTypeface, in the non-USE_MINIKIN case.
+// TODO: when #ifdef USE_MINIKIN is removed, move to member functions.
+
+TypefaceImpl* TypefaceImpl_resolveDefault(TypefaceImpl* src);
+#else
+typedef SkTypeface TypefaceImpl;
+#endif
+
+TypefaceImpl* TypefaceImpl_createFromTypeface(TypefaceImpl* src, SkTypeface::Style style);
+
+TypefaceImpl* TypefaceImpl_createFromName(const char* name, SkTypeface::Style style);
+
+TypefaceImpl* TypefaceImpl_createFromFile(const char* filename);
+
+TypefaceImpl* TypefaceImpl_createFromAsset(Asset* asset);
+
+void TypefaceImpl_unref(TypefaceImpl* face);
+
+int TypefaceImpl_getStyle(TypefaceImpl* face);
+
+}
+
+#endif  // ANDROID_TYPEFACE_IMPL_H
\ No newline at end of file
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index b57a0fe..6175a8f 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -17,62 +17,138 @@
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
+#include <vector>
+
+#include "CreateJavaOutputStreamAdaptor.h"
 
 #include "SkCanvas.h"
-#include "SkPDFDevice.h"
-#include "SkPDFDocument.h"
+#include "SkDocument.h"
+#include "SkPicture.h"
+#include "SkStream.h"
 #include "SkRect.h"
-#include "SkSize.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-#include "JNIHelp.h"
 
 namespace android {
 
-#define LOGD(x...) do { Log::Instance()->printf(Log::ELogD, x); } while(0)
+struct PageRecord {
 
-static jint nativeCreateDocument(JNIEnv* env, jobject clazz) {
-    return reinterpret_cast<jint>(new SkPDFDocument());
+    PageRecord(int width, int height, const SkRect& contentRect)
+            : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
+        mContentRect = contentRect;
+    }
+
+    ~PageRecord() {
+        mPicture->unref();
+    }
+
+    SkPicture* const mPicture;
+    const int mWidth;
+    const int mHeight;
+    SkRect mContentRect;
+};
+
+class PdfDocument {
+public:
+    PdfDocument() {
+        mCurrentPage = NULL;
+    }
+
+    SkCanvas* startPage(int width, int height,
+            int contentLeft, int contentTop, int contentRight, int contentBottom) {
+        assert(mCurrentPage == NULL);
+
+        SkRect contentRect = SkRect::MakeLTRB(
+                contentLeft, contentTop, contentRight, contentBottom);
+        PageRecord* page = new PageRecord(width, height, contentRect);
+        mPages.push_back(page);
+        mCurrentPage = page;
+
+        SkCanvas* canvas = page->mPicture->beginRecording(
+                contentRect.width(), contentRect.height(), 0);
+
+        // We pass this canvas to Java where it is used to construct
+        // a Java Canvas object which dereferences the pointer when it
+        // is destroyed, so we have to bump up the reference count.
+        canvas->ref();
+
+        return canvas;
+    }
+
+    void finishPage() {
+        assert(mCurrentPage != NULL);
+        mCurrentPage->mPicture->endRecording();
+        mCurrentPage = NULL;
+    }
+
+    void write(SkWStream* stream) {
+        SkDocument* document = SkDocument::CreatePDF(stream);
+        for (unsigned i = 0; i < mPages.size(); i++) {
+            PageRecord* page =  mPages[i];
+
+            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
+                    &(page->mContentRect));
+
+            canvas->clipRect(page->mContentRect);
+            canvas->translate(page->mContentRect.left(), page->mContentRect.top());
+            canvas->drawPicture(*page->mPicture);
+
+            document->endPage();
+        }
+        document->close();
+    }
+
+    void close() {
+        for (unsigned i = 0; i < mPages.size(); i++) {
+            delete mPages[i];
+        }
+        delete mCurrentPage;
+        mCurrentPage = NULL;
+    }
+
+private:
+    ~PdfDocument() {
+        close();
+    }
+
+    std::vector<PageRecord*> mPages;
+    PageRecord* mCurrentPage;
+};
+
+static jint nativeCreateDocument(JNIEnv* env, jobject thiz) {
+    return reinterpret_cast<jint>(new PdfDocument());
 }
 
-static void nativeFinalize(JNIEnv* env, jobject thiz, jint documentPtr) {
-    delete reinterpret_cast<SkPDFDocument*>(documentPtr);
-}
-
-static jint nativeCreatePage(JNIEnv* env, jobject thiz, jint pageWidth, jint pageHeight,
+static jint nativeStartPage(JNIEnv* env, jobject thiz, jint documentPtr,
+        jint pageWidth, jint pageHeight,
         jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
-
-    SkMatrix transformation;
-    transformation.setTranslate(contentLeft, contentTop);
-
-    SkISize skPageSize = SkISize::Make(pageWidth, pageHeight);
-    SkISize skContentSize = SkISize::Make(contentRight - contentLeft, contentBottom - contentTop);
-
-    SkPDFDevice* skPdfDevice = new SkPDFDevice(skPageSize, skContentSize, transformation);
-    return reinterpret_cast<jint>(new SkCanvas(skPdfDevice));
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
+    return reinterpret_cast<jint>(document->startPage(pageWidth, pageHeight,
+            contentLeft, contentTop, contentRight, contentBottom));
 }
 
-static void nativeAppendPage(JNIEnv* env, jobject thiz, jint documentPtr, jint pagePtr) {
-    SkCanvas* page = reinterpret_cast<SkCanvas*>(pagePtr);
-    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
-    SkPDFDevice* device = static_cast<SkPDFDevice*>(page->getDevice());
-    document->appendPage(device);
+static void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) {
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
+    document->finishPage();
 }
 
-static void nativeWriteTo(JNIEnv* env, jobject clazz, jint documentPtr,
-        jobject out, jbyteArray chunk) {
+static void nativeWriteTo(JNIEnv* env, jobject thiz, jint documentPtr, jobject out,
+        jbyteArray chunk) {
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
     SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
-    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
-    document->emitPDF(skWStream);
+    document->write(skWStream);
     delete skWStream;
 }
 
+static void nativeClose(JNIEnv* env, jobject thiz, jint documentPtr) {
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
+    document->close();
+}
+
 static JNINativeMethod gPdfDocument_Methods[] = {
     {"nativeCreateDocument", "()I", (void*) nativeCreateDocument},
-    {"nativeFinalize", "(I)V", (void*) nativeFinalize},
-    {"nativeCreatePage", "(IIIIII)I",
-            (void*) nativeCreatePage},
-    {"nativeAppendPage", "(II)V", (void*) nativeAppendPage},
-    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo}
+    {"nativeStartPage", "(IIIIIII)I", (void*) nativeStartPage},
+    {"nativeFinishPage", "(I)V", (void*) nativeFinishPage},
+    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
+    {"nativeClose", "(I)V", (void*) nativeClose}
 };
 
 int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
similarity index 76%
rename from core/jni/android_view_HardwareRenderer.cpp
rename to core/jni/android_view_GLRenderer.cpp
index 479fbe2..7cf93d0 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "HardwareRenderer"
+#define LOG_TAG "GLRenderer"
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -60,7 +60,7 @@
 // Surface and display management
 // ----------------------------------------------------------------------------
 
-static jboolean android_view_HardwareRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) {
+static jboolean android_view_GLRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) {
     EGLDisplay display = eglGetCurrentDisplay();
     EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
 
@@ -75,7 +75,7 @@
     return error == EGL_SUCCESS;
 }
 
-static jboolean android_view_HardwareRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
+static jboolean android_view_GLRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
     EGLDisplay display = eglGetCurrentDisplay();
     EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
     EGLint value;
@@ -95,14 +95,14 @@
 // Tracing and debugging
 // ----------------------------------------------------------------------------
 
-static bool android_view_HardwareRenderer_loadProperties(JNIEnv* env, jobject clazz) {
+static bool android_view_GLRenderer_loadProperties(JNIEnv* env, jobject clazz) {
     if (uirenderer::Caches::hasInstance()) {
         return uirenderer::Caches::getInstance().initProperties();
     }
     return false;
 }
 
-static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz,
+static void android_view_GLRenderer_beginFrame(JNIEnv* env, jobject clazz,
         jintArray size) {
 
     EGLDisplay display = eglGetCurrentDisplay();
@@ -124,7 +124,7 @@
     eglBeginFrame(display, surface);
 }
 
-static jlong android_view_HardwareRenderer_getSystemTime(JNIEnv* env, jobject clazz) {
+static jlong android_view_GLRenderer_getSystemTime(JNIEnv* env, jobject clazz) {
     if (uirenderer::Extensions::getInstance().hasNvSystemTime()) {
         return eglGetSystemTimeNV();
     }
@@ -137,7 +137,7 @@
 // Shaders
 // ----------------------------------------------------------------------------
 
-static void android_view_HardwareRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
+static void android_view_GLRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
         jstring diskCachePath) {
 
     const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
@@ -149,24 +149,24 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-const char* const kClassPathName = "android/view/HardwareRenderer";
+const char* const kClassPathName = "android/view/GLRenderer";
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
-    { "nIsBackBufferPreserved", "()Z",   (void*) android_view_HardwareRenderer_isBackBufferPreserved },
-    { "nPreserveBackBuffer",    "()Z",   (void*) android_view_HardwareRenderer_preserveBackBuffer },
-    { "nLoadProperties",        "()Z",   (void*) android_view_HardwareRenderer_loadProperties },
+    { "isBackBufferPreserved", "()Z",   (void*) android_view_GLRenderer_isBackBufferPreserved },
+    { "preserveBackBuffer",    "()Z",   (void*) android_view_GLRenderer_preserveBackBuffer },
+    { "loadProperties",        "()Z",   (void*) android_view_GLRenderer_loadProperties },
 
-    { "nBeginFrame",            "([I)V", (void*) android_view_HardwareRenderer_beginFrame },
+    { "beginFrame",            "([I)V", (void*) android_view_GLRenderer_beginFrame },
 
-    { "nGetSystemTime",         "()J",   (void*) android_view_HardwareRenderer_getSystemTime },
+    { "getSystemTime",         "()J",   (void*) android_view_GLRenderer_getSystemTime },
 #endif
 
-    { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
-            (void*) android_view_HardwareRenderer_setupShadersDiskCache },
+    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
+            (void*) android_view_GLRenderer_setupShadersDiskCache },
 };
 
-int register_android_view_HardwareRenderer(JNIEnv* env) {
+int register_android_view_GLRenderer(JNIEnv* env) {
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index 44452f0..2233ee3 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -159,29 +159,6 @@
     }
 }
 
-static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
-    jobject clazz, jint pid)
-{
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata;
-    int err;
-
-    memset (&capheader, 0, sizeof(capheader));
-    memset (&capdata, 0, sizeof(capdata));
-
-    capheader.version = _LINUX_CAPABILITY_VERSION;
-    capheader.pid = pid;
-
-    err = capget (&capheader, &capdata);
-
-    if (err < 0) {
-        jniThrowIOException(env, errno);
-        return 0;
-    }
-
-    return (jlong) capdata.permitted;
-}
-
 static jint com_android_internal_os_ZygoteInit_selectReadable (
         JNIEnv *env, jobject clazz, jobjectArray fds)
 {
@@ -274,8 +251,6 @@
             (void *) com_android_internal_os_ZygoteInit_reopenStdio},
     { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
         (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
-    { "capgetPermitted", "(I)J",
-        (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
     { "selectReadable", "([Ljava/io/FileDescriptor;)I",
         (void *) com_android_internal_os_ZygoteInit_selectReadable },
     { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f0fc9e3..c923e14 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"
@@ -2521,7 +2529,7 @@
                  android:hasCode="false"
                  android:label="@string/android_system_label"
                  android:allowClearUserData="false"
-                 android:backupAgent="com.android.server.SystemBackupAgent"
+                 android:backupAgent="com.android.server.backup.SystemBackupAgent"
                  android:killAfterRestore="false"
                  android:icon="@drawable/ic_launcher_android"
                  android:supportsRtl="true">
@@ -2688,6 +2696,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-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index ca65994..a804a8a 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
deleted file mode 100644
index a804a8a..0000000
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/toast_frame.9.png b/core/res/res/drawable-ldpi/toast_frame.9.png
index 3b344ff..e64dc75 100644
--- a/core/res/res/drawable-ldpi/toast_frame.9.png
+++ b/core/res/res/drawable-ldpi/toast_frame.9.png
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-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 9e93fe7..778e4e6 100644
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
deleted file mode 100644
index 778e4e6..0000000
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.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-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
index 1f63420..77e69c7 100644
--- a/core/res/res/drawable-xhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
deleted file mode 100644
index 77e69c7..0000000
--- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.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-xxhdpi/toast_frame.9.png b/core/res/res/drawable-xxhdpi/toast_frame.9.png
index 882b9c6..edecb63 100644
--- a/core/res/res/drawable-xxhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xxhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
deleted file mode 100644
index edecb63..0000000
--- a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.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 f063a0a..37ac2ca 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Invoersleutel"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Kies \'n program"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Kon <xliff:g id="APPLICATION_NAME">%s</xliff:g> nie begin nie"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Deel met"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Deel met <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Skyfievatsel. Raak en hou."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 786b5e4..5561501 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -210,7 +210,7 @@
     <string name="permgroupdesc_camera" msgid="2933667372289567714">"ለካሜራ ምስል ወይም ቪዲዮ ለመቅረጽ ቀጥተኛ መዳረሻ።"</string>
     <string name="permgrouplab_screenlock" msgid="8275500173330718168">"ማያ ገጽ ቆልፍ"</string>
     <string name="permgroupdesc_screenlock" msgid="7067497128925499401">"በመሣሪያዎ ላይ ያለውን የመቆለፊያ ማያ ገጽ ባህሪያት ላይ ተጽዕኖ የመፍጠር ችሎታ።"</string>
-    <string name="permgrouplab_appInfo" msgid="8028789762634147725">"የመተግበሪያዎችህ መረጃ"</string>
+    <string name="permgrouplab_appInfo" msgid="8028789762634147725">"የመተግበሪያዎችዎ መረጃ"</string>
     <string name="permgroupdesc_appInfo" msgid="3950378538049625907">"በመሣሪያህ ላይ ያሉ የሌሎች መተግበሪያዎች ባህሪዎች ላይ ተፅዕኖ የማሳረፍ ችሎታ።"</string>
     <string name="permgrouplab_wallpaper" msgid="3850280158041175998">"ልጣፍ"</string>
     <string name="permgroupdesc_wallpaper" msgid="5630417854750540154">"የመሣሪያውን ልጣፍ ቅንብሮች ቀይር።"</string>
@@ -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>
@@ -277,7 +277,7 @@
     <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"በስልክህ ወይም ሲም ካርድህ ላይ ኤስ ኤም ኤስ መልዕክቶችን ለመፃፍ ለመተግበሪያው ይፈቅዳሉ፡፡መልዕክቶችህን ተንኮል አዘል መተግበሪያዎች ሊሰርዙ ይችላሉ፡፡"</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"የፅሁፍ መልዕክቶችን ተቀበል (WAP)"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"መተግበሪያው የWAP መልእክቶችን እንዲያነብ እና እንዲያካሂድ ይፈቅዳል። ይህ ፈቃድ የተላኩልህን መልእክቶች ላንተ ሳያሳይህ የመቆጣጠር ወይም የመሰረዝ ብቃትን ያጠቃልላል።"</string>
-    <string name="permlab_getTasks" msgid="6466095396623933906">"አሂድ መተግበሪያዎችን ሰርስረህ አውጣ"</string>
+    <string name="permlab_getTasks" msgid="6466095396623933906">"አሂድ መተግበሪያዎችን ሰርስረው ያውጡ"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"መተግበሪያው በአሁኑ ጊዜና በቅርቡ እየተካሄዱ ስላሉ ተግባሮችን መረጃ ሰርስሮ እንዲያወጣ ይፈቅድለታል። ይህ መተግበሪያው በመሳሪያው ላይ የትኛዎቹ መተግበሪያዎች ጥቅም ላይ ስለመዋላቸው መረጃ እንዲያገኝ ሊፈቅድለት ይችላል።"</string>
     <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር መፍጠር"</string>
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"መተግበሪያው በመሣሪያው ላይ በተለያዩ ተጠቃሚዎች ላይ እርምጃዎችን እንዲፈጽም ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች ይህንን ተጠቅመው በተጠቃሚዎች መካከል ያለውን ጥበቃ ሊጥሱ ይችላሉ።"</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>
@@ -500,9 +502,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>
@@ -585,16 +587,16 @@
     <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="permlab_useCredentials" msgid="235481396163877642">"በመሣሪያው ላይ ያሉ መለያዎችን ይጠቀሙ"</string>
     <string name="permdesc_useCredentials" msgid="7984227147403346422">"የማረጋገጫ የምስጋና የምስክር ወረቀትን ለመጠየቅ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
-    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"የአውታረ መረብ ግኑኝነቶችን እይ"</string>
+    <string name="permlab_accessNetworkState" msgid="4951027964348974773">"የአውታረ መረብ ግንኙነቶችን ይመልከቱ"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"መተግበሪያው እንደ የትኛዎቹ አውታረ መረቦች እንዳሉ እና እንደተገናኙ ያሉ የአውታረ መረብ ግንኙነቶች መረጃዎችን እንዲያይ ይፈቅድለታል።"</string>
     <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ሙሉ የአውታረ መረብ መዳረሻ"</string>
     <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"መተግበሪያው የአውታረ መረብ መሰኪያዎችን እንዲፈጥር እና ብጁ የአውታረ መረብ ፕሮቶኮሎችን እንዲጠቀም ይፈቅድለታል። አሳሹ እና ሌሎች መተግበሪያዎች ውሂብ ወደ በይነመረብ የመላኪያ መንገዶችን ስለሚያቀርቡውሂብ ወደ በይነመረብ ለመላክ ይህ ፍቃድ አያስፈልግም።"</string>
@@ -645,7 +647,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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ቀይር"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"አስገባ"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"መተግበሪያ ምረጥ"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>ን ማስጀመር አልተቻለም"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"ተጋራ ከ"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"ከ <xliff:g id="APPLICATION_NAME">%s</xliff:g> ጋር ተጋራ"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"ባለስላይድ መያዣ፡፡ ዳስ&amp;ያዝ፡፡"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 bc0b95f..abb1b39 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"العالي"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"اختيار تطبيق"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"تعذر تشغيل <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"مشاركة مع"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"مشاركة مع <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"مقبض التمرير. المس مع الاستمرار."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 4be2487..0547c6e 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>
@@ -1540,8 +1544,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>
@@ -1554,8 +1565,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 0d6ee71..afaa345 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Изберете приложение"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> не можа да се стартира"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Споделяне със"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Споделяне със: <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Плъзгаща се дръжка. Докоснете и задръжте."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 617209f..d0ebba8 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Retorn"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Selecciona una aplicació"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"No s\'ha pogut iniciar <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Comparteix amb"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Comparteix amb <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Llisca el dit. Mantén premut."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 ca25ddc..3bc6b28 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Vybrat aplikaci"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Aplikaci <xliff:g id="APPLICATION_NAME">%s</xliff:g> nelze spustit."</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Sdílet s"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Sdílet s aplikací <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Posuvník. Dotkněte se a podržte."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 c793249..80d8b6c 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>
@@ -1121,7 +1123,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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Angiv"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Vælg en app"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> kunne ikke startes"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Del med"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Del med <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Glidende håndtag. Tryk og hold nede."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 52bbaa3..e857a60 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Umschalttaste"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Eingabetaste"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"App auswählen"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> konnte nicht gestartet werden."</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Teilen mit"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Mit <xliff:g id="APPLICATION_NAME">%s</xliff:g> teilen"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Schieberegler: Berühren und halten"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 7371012..59efe1b 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Επιλέξτε κάποια εφαρμογή"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Δεν ήταν δυνατή η εκκίνηση του <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Κοινή χρήση με"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Κοινή χρήση με <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Στοιχείο χειρισμού με δυνατότητα ολίσθησης. Αγγίξτε και πατήστε παρατεταμένα."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 5f49013..c0cacf1 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Choose an app"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Couldn\'t launch <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Share with"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Share with <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Sliding handle. Touch &amp; hold."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 5f49013..c0cacf1 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Choose an app"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Couldn\'t launch <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Share with"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Share with <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Sliding handle. Touch &amp; hold."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 b980926..2c73183 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Mayúscula"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ingresar"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Elige una aplicación."</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"No se pudo abrir <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Compartir con"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Compartir con <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Mantén presionado el controlador deslizante."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 6a936e1..bd2f4b9 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>
@@ -790,7 +792,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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Mayús"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Intro"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Seleccionar una aplicación"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"No se ha podido abrir <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Compartir con"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Compartir con <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Mantén pulsado el icono de desbloqueo y deslízalo."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 c792889..f7b3e0a 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tõstuklahv"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Sisestusklahv"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Valige rakendus"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Rakendust <xliff:g id="APPLICATION_NAME">%s</xliff:g> ei õnnestunud käivitada"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Jaga:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Jaga rakendusega <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Libistamispide. Puudutage ja hoidke all."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 719dafe..7bd87ba 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"انتخاب برنامه"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"راه‌اندازی <xliff:g id="APPLICATION_NAME">%s</xliff:g> انجام نشد"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"اشتراک‌گذاری با"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"اشتراک‌گذاری با <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"اهرم کنترل حرکت. لمس کرده و نگهدارید."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 2008e75..0b0abe2 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Valitse sovellus"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ei käynnisty"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Jaa seuraavien kanssa:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Jaa sovelluksessa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Liukuva valitsin. Kosketa pitkään."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 a2dd82f..3b91029 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>
@@ -790,7 +792,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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Entrée"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Sélectionnez une application"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Impossible de lancer l\'application <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Partagez avec"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Partager avec <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Poignée coulissante. Appuyez de manière prolongée."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 f5a7ffd..f665974 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maj"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Entrée"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Sélectionnez une application"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Impossible de lancer l\'application <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Partager avec"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Partager avec <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Poignée coulissante. Appuyez de manière prolongée."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 e883c23..1f01575 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"कोई ऐप्स चुनें"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> को लॉन्च नहीं किया जा सका"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"इसके साथ साझा करें:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"स्लाइडिंग हैंडल. स्पर्श करके रखें."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 df84a5e..9134725 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Odabir aplikacije"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nije moguće pokrenuti aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Dijeljenje sa"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Dijeli s aplikacijom <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Klizna ručka. Dodirnite i držite."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 fb4d3a3..47a42e5 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Válasszon ki egy alkalmazást"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"A(z) <xliff:g id="APPLICATION_NAME">%s</xliff:g> alkalmazást indítása nem sikerült"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Megosztás a következővel:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Ossza meg a következő alkalmazással: <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Csúsztatható fogantyú. Érintse meg és tartsa."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 f6e71bb..cf9a75d 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Մուտք"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Ընտրել ծրագիր"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Չհաջողվեց գործարկել <xliff:g id="APPLICATION_NAME">%s</xliff:g> ծրագիրը"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Տարածել"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Համօգտագործել <xliff:g id="APPLICATION_NAME">%s</xliff:g>-ի հետ"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Սահող բռնակ: Հպել &amp; պահել:"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 f47680d..3d67e3d 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>
@@ -1149,15 +1151,15 @@
     <string name="smv_application" msgid="3307209192155442829">"Apl <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) telah melanggar kebijakan StrictMode yang diberlakukannya sendiri."</string>
     <string name="smv_process" msgid="5120397012047462446">"Proses <xliff:g id="PROCESS">%1$s</xliff:g> telah melanggar kebijakan StrictMode yang diberlakukan secara otomatis."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android sedang meningkatkan versi..."</string>
-    <string name="android_upgrading_apk" msgid="7904042682111526169">"Mengoptimalkan apl <xliff:g id="NUMBER_0">%1$d</xliff:g> dari <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulai apl."</string>
+    <string name="android_upgrading_apk" msgid="7904042682111526169">"Mengoptimalkan aplikasi <xliff:g id="NUMBER_0">%1$d</xliff:g> dari <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+    <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Memulai aplikasi."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Menyelesaikan boot."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> berjalan"</string>
     <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Sentuh untuk beralih ke apl"</string>
     <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Beralih apl?"</string>
     <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Apl lain sudah berjalan dan harus dihentikan agar Anda dapat memulai yang baru."</string>
     <string name="old_app_action" msgid="493129172238566282">"Kembali ke<xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
-    <string name="old_app_description" msgid="2082094275580358049">"Jangan memulai apl baru."</string>
+    <string name="old_app_description" msgid="2082094275580358049">"Jangan memulai aplikasi baru."</string>
     <string name="new_app_action" msgid="5472756926945440706">"Mulai <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Hentikan apl lama tanpa menyimpan."</string>
     <string name="sendText" msgid="5209874571959469142">"Pilih tindakan untuk teks"</string>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Pilih apl"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Tidak dapat meluncurkan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Berbagi dengan"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Berbagi dengan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Gagang geser. Sentuh &amp; tahan."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 9ad07cd..7cd1b69 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -52,8 +52,8 @@
     <string name="needPuk2" msgid="4526033371987193070">"Digita il PUK2 per sbloccare la SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Operazione non riuscita; attiva blocco SIM/RUIM."</string>
   <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Hai <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata."</item>
-    <item quantity="other" msgid="7530597808358774740">"Hai <xliff:g id="NUMBER">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata."</item>
+    <item quantity="one" msgid="6596245285809790142">"Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione prima che la SIM venga bloccata."</item>
+    <item quantity="other" msgid="7530597808358774740">"Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativi a disposizione prima che la SIM venga bloccata."</item>
   </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Maiuscolo"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Invio"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Scegli un\'applicazione"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Impossibile avviare l\'applicazione <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Condividi con"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Condividi con <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Maniglia scorrevole. Tocca e tieni premuto."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 6b5dabf..cae8711 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"בחר אפליקציה"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"לא ניתן היה להפעיל את <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"שתף עם"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"שתף עם <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"ידית להחלקה. גע והחזק."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 58129c9..53569da 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"アプリの選択"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>を起動できませんでした"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"共有"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>と共有"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"スライダーハンドルです。押し続けます。"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 6f4a175..b450063 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift-"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"შეყვანა"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"აპის არჩევა"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ვერ გაეშვა"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"გაზიარება"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"გაუზიარეთ <xliff:g id="APPLICATION_NAME">%s</xliff:g>-ს"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"გასრიალებით მართვა. შეეხეთ &amp; არ აუშვათ."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 e6e5148..d414212 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>
@@ -790,7 +792,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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ជ្រើស​កម្មវិធី"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"មិន​អាច​ចាប់ផ្ដើម <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"ចែករំលែក​ជា​មួយ"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"ចែក​រំលែក​ជា​មួយ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"គ្រប់គ្រង​ការ​រុញ។ ប៉ះ &amp; សង្កត់។"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 cd212e3..740c74d 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 키"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 키"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"앱 선택"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>을(를) 실행할 수 없습니다."</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"공유 대상:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>와(과) 공유"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"슬라이딩 핸들을 길게 터치하세요."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 c430596..0a89921 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"ເລືອກແອັບຯ"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"ບໍ່​ສາ​ມາດ​ເປີດ <xliff:g id="APPLICATION_NAME">%s</xliff:g> ໄດ້"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"ແບ່ງປັນກັບ"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"ແບ່ງປັນໃຫ້ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"ເລື່ອນບ່ອນຖື ແລ້ວແຕະຄ້າງໄວ້."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 40a4284..edc1b2f 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Įvesti"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Pasirinkite programą"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nepavyko paleisti „<xliff:g id="APPLICATION_NAME">%s</xliff:g>“"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Bendrinti su"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Bendrinti su „<xliff:g id="APPLICATION_NAME">%s</xliff:g>“"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Slydimo valdymas. Palieskite ir laikykite."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 77ac05c..e06c268 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Pārslēgšanas taustiņš"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ievadīšanas taustiņš"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Izvēlieties lietotni"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nevarēja palaist lietotni <xliff:g id="APPLICATION_NAME">%s</xliff:g>."</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Kopīgot ar:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Kopīgot ar lietojumprogrammu <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Bīdāms turis. Pieskarieties tam un turiet to nospiestu."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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-mcc311-mnc190/config.xml b/core/res/res/values-mcc311-mnc190/config.xml
new file mode 100644
index 0000000..a6c4d1b
--- /dev/null
+++ b/core/res/res/values-mcc311-mnc190/config.xml
@@ -0,0 +1,40 @@
+<?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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     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">Tether,broadband.cellular1.net,,,,,,,,,311,190,,DUN</string>
+
+</resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 5da651e..4f4696e 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>
@@ -790,7 +792,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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Шифт"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Оруулах"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Апп сонгох"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>-г эхлүүлж чадсангүй"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Хуваалцах"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>-тай хуваалцана уу"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Бариулыг гулсуулна. Хүрээд хүлээнэ."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 a013557..53e3e6c 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -52,8 +52,8 @@
     <string name="needPuk2" msgid="4526033371987193070">"Taipkan PUK2 untuk menyahsekat kad SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Tidak berjaya, dayakan Kunci SIM/RUIM."</string>
   <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan yang tinggal sebelum SIM dikunci."</item>
-    <item quantity="other" msgid="7530597808358774740">"Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan yang tinggal sebelum SIM dikunci."</item>
+    <item quantity="one" msgid="6596245285809790142">"Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM dikunci."</item>
+    <item quantity="other" msgid="7530597808358774740">"Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM dikunci."</item>
   </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
     <string name="meid" msgid="4841221237681254195">"MEID"</string>
@@ -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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Masuk"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Pilih apl"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Tidak dapat melancarkan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Kongsi dengan"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Kongsi dengan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Pemegang gelongsor. Sentuh &amp; tahan."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 7254693..d5856b0 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Velg en app"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Kunne ikke starte <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Del med"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Del med <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Glidebryter. Trykk og hold inne."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 2fdabcd8..4323d72 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Een app selecteren"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Kan <xliff:g id="APPLICATION_NAME">%s</xliff:g> niet starten"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Delen met"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Delen met <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Schuifgreep. Tikken en blijven aanraken."</string>
@@ -1491,9 +1492,13 @@
     <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
     <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 display"</string>
-    <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gereed"</string>
+    <string name="wireless_display_route_description" msgid="9070346425023979651">"Draadloze weergave"</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>
@@ -1504,8 +1509,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 display 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 6ace506..3b29784 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>
@@ -1211,7 +1213,7 @@
     <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> telefon zostanie tymczasowo odłączony od Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
-    <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; wysyła wiele SMS-ów. Chcesz pozwolić tej aplikacji dalej wysyłać SMS-y?"</string>
+    <string name="sms_control_message" msgid="3867899169651496433">"Aplikacja &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; wysyła wiele SMS-ów. Chcesz pozwolić tej aplikacji dalej wysyłać SMS-y?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"Pozwól"</string>
     <string name="sms_control_no" msgid="625438561395534982">"Odmów"</string>
     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; chce wysłać wiadomość do &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Wybierz aplikację"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nie udało się uruchomić aplikacji <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Udostępnij przez"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Udostępnij przez <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Uchwyt przesuwny. Dotknij i przytrzymaj."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 d831a4d..6441f76 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Escolher uma aplicação"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Não foi possível iniciar <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Partilhar com:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Compartilhar com <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Barra deslizante. Toque &amp; não solte."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 56dbd2a..0942372 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Selecione um aplicativo"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Não foi possível iniciar o <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Compartilhar com"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Compartilhar com <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Recurso deslizante. Toque e segure."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 48ff2a5..fdc04eb 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) -->
@@ -2415,10 +2419,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) -->
@@ -2439,9 +2451,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 9d57b5a..f61358c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -50,7 +50,7 @@
     <string name="invalidPuk" msgid="8761456210898036513">"Introduceţi un cod PUK care să aibă 8 cifre sau mai mult."</string>
     <string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceţi codul PUK pentru a-l debloca."</string>
     <string name="needPuk2" msgid="4526033371987193070">"Introduceţi codul PUK2 pentru a debloca cardul SIM."</string>
-    <string name="enablePin" msgid="209412020907207950">"Operațiunea nu a reușit, activați blocarea cardului SIM/RUIM."</string>
+    <string name="enablePin" msgid="209412020907207950">"Operațiunea nu a reușit. Activați blocarea cardului SIM/RUIM."</string>
   <plurals name="pinpuk_attempts">
     <item quantity="one" msgid="6596245285809790142">"V-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare până la blocarea cardului SIM."</item>
     <item quantity="other" msgid="7530597808358774740">"V-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări până la blocarea cardului SIM."</item>
@@ -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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Alegeţi o aplicaţie"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nu s-a putut lansa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Permiteţi accesul pentru"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Permiteţi accesul pentru <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Mâner glisant. Atingeţi şi ţineţi apăsat."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 73bbb72..431c454 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>
@@ -1350,7 +1352,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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Клавиша смены регистра"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Клавиша ввода"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Выберите приложение"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Не удалось запустить приложение \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\""</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Открыть доступ:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Открыть доступ приложению \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\""</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Перетаскиваемый значок блокировки. Нажмите и удерживайте."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 d36c178..05758fe 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Zvoľte aplikáciu"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Aplikáciu <xliff:g id="APPLICATION_NAME">%s</xliff:g> nie je možné spustiť"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Zdieľať s"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Zdieľať s aplikáciou <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Posuvné tlačidlo. Dotknite sa a podržte."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 e409605..a4ba532 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -52,7 +52,7 @@
     <string name="needPuk2" msgid="4526033371987193070">"Če želite odstraniti blokiranje kartice SIM, vnesite PUK2."</string>
     <string name="enablePin" msgid="209412020907207950">"Ni uspelo. Omogočite zaklepanje kartice SIM/RUIM."</string>
   <plurals name="pinpuk_attempts">
-    <item quantity="one" msgid="6596245285809790142">"Imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem se bo kartica SIM zaklenila."</item>
+    <item quantity="one" msgid="6596245285809790142">"Na voljo imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem se bo kartica SIM zaklenila."</item>
     <item quantity="other" msgid="7530597808358774740">"Poskusite lahko še <xliff:g id="NUMBER">%d</xliff:g>-krat. Potem se bo kartica SIM zaklenila."</item>
   </plurals>
     <string name="imei" msgid="2625429890869005782">"IMEI"</string>
@@ -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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Tipka Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Tipka Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Izberite program"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Aplikacije <xliff:g id="APPLICATION_NAME">%s</xliff:g> ni bilo mogoče zagnati"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Delite z"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Delite s programom <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Drsna ročica. Dotaknite se in pridržite."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 1cf3fad..b3ec8e3 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Изаберите апликацију"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Није могуће покренути <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Дели са"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Дели са апликацијом <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Клизна ручица. Додирните и задржите."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 a77df18..b8975af 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Skift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Retur"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Välj en app"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Det gick inte att starta <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Dela med"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Dela med <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Skärmlåsfunktion. Tryck och dra."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 9a4ac1f..b2b61d0 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>
@@ -558,7 +560,7 @@
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"kusoma hali na kitambulisho cha simu"</string>
     <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Inaruhusu programu kufikia vipengele vya simu vya kifaa. Idhini hii inaruhusu programu kutambua nambari ya simu na kifaa, kama simu ni amilifu, na nambari ya mbali iliyounganishwa kwa simu."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zuia kompyuta ndogo dhidi ya kulala"</string>
-    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zuia simu dhidi ya kulala"</string>
+    <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"kuzuia simu isilale"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao  kwenda kulala."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Inaruhusu programu kuzuia simu isiende kulala."</string>
     <string name="permlab_transmitIr" msgid="7545858504238530105">"sambaza infrared"</string>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Chagua programu"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Haikuweza kuzindua <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Shiriki na"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Shiriki na <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Utambo unaosonga. Gusa &amp; shika"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 608dd2d..51b0ad5 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"ป้อน"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"เลือกแอปพลิเคชัน"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"ไม่สามารถเปิด <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"แบ่งปันกับ"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"แบ่งปันด้วย <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"ที่จับสำหรับเลื่อน แตะค้างไว้"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 1d794c8..f5f2967 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Pumili ng isang app"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Hindi mailunsad ang <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Ibahagi sa"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Ibahagi sa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Hawakan sa pag-slide. Pindutin nang matagal."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 5cc1435..283a19b 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"ÜstKrkt"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Giriş"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Bir uygulama seçin"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> başlatılamadı"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Şununla paylaş:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> ile paylaş"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Kayan tutma yeri. Dokunun ve basılı tutun."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 d5c6da9..9089211 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Вибрати програму"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Не вдалося запустити програму <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Надіслати через"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Надіслати через <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Вказівник-повзунок. Торкніться й утримуйте."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 94106ab..0647fdb 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Chọn một ứng dụng"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Không thể khởi chạy <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Chia sẻ với"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Chia sẻ với <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Tay trượt. Chạm &amp; giữ."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 4aa34536..f694a14 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>
@@ -490,8 +492,8 @@
     <string name="permdesc_controlWifiDisplay" msgid="4543912292681826986">"允许应用控制 WLAN 显示设备的基础功能。"</string>
     <string name="permlab_captureAudioOutput" msgid="6857134498402346708">"捕获音频输出"</string>
     <string name="permdesc_captureAudioOutput" msgid="6210597754212208853">"允许该应用捕获和重定向音频输出。"</string>
-    <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"检测关键词"</string>
-    <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允许应用捕获音频以便检测语音指令的关键词。捕获操作会在后台进行,但不会妨碍其他音频捕获工具(例如摄像机)。"</string>
+    <string name="permlab_captureAudioHotword" msgid="1890553935650349808">"启动指令检测"</string>
+    <string name="permdesc_captureAudioHotword" msgid="9151807958153056810">"允许应用捕获音频以便检测语音启动指令。捕获操作会在后台进行,但不会妨碍其他音频捕获工具(例如摄像机)。"</string>
     <string name="permlab_captureVideoOutput" msgid="2246828773589094023">"捕获视频输出"</string>
     <string name="permdesc_captureVideoOutput" msgid="359481658034149860">"允许该应用捕获和重定向视频输出。"</string>
     <string name="permlab_captureSecureVideoOutput" msgid="7815398969303382016">"捕获安全视频输出"</string>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"选择应用"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"无法启动“<xliff:g id="APPLICATION_NAME">%s</xliff:g>”"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"分享方式"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"使用<xliff:g id="APPLICATION_NAME">%s</xliff:g>分享"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"滑动手柄。触摸并按住。"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 f74d5a8..eaa859a 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 鍵"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 鍵"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"選擇應用程式"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"無法啟動 <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"分享給"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"與「<xliff:g id="APPLICATION_NAME">%s</xliff:g>」分享"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"滑動控制。持續輕觸。"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 1bd2943..a7626f5 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift 鍵"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter 鍵"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"選擇應用程式"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"無法啟動 <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"分享對象:"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"與「<xliff:g id="APPLICATION_NAME">%s</xliff:g>」分享"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"滑動控制。持續輕觸。"</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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 b0dbd2c..a6d0e64 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>
@@ -1421,8 +1423,7 @@
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Beka kwenye indawo"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Faka"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Khetha uhlelo lokusebenza"</string>
-    <!-- no translation found for activitychooserview_choose_application_error (8624618365481126668) -->
-    <skip />
+    <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Ayikwazanga ukuqalisa i-<xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="806688056141131819">"Yabelana no"</string>
     <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Yabelana no <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="content_description_sliding_handle" msgid="415975056159262248">"Ihaambis isibambo. Thinta &amp; ubambe."</string>
@@ -1492,8 +1493,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>
@@ -1504,8 +1509,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/arrays.xml b/core/res/res/values/arrays.xml
index ef30b98..91af50a 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,7 +22,7 @@
     <!-- Do not translate. These are all of the drawable resources that should be preloaded by
          the zygote process before it starts forking application processes. -->
     <array name="preloaded_drawables">
-       <item>@drawable/toast_frame_holo</item>
+       <item>@drawable/toast_frame</item>
        <item>@drawable/btn_check_on_pressed_holo_light</item>
        <item>@drawable/btn_check_on_pressed_holo_dark</item>
        <item>@drawable/btn_check_on_holo_light</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7254403..28f5796 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -447,6 +447,15 @@
              to {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION}. -->
         <attr name="windowTranslucentNavigation" format="boolean" />
 
+        <!-- Flag indicating whether this window requests that content changes be performed
+             as scene changes with transitions. Corresponds to
+             {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS}. -->
+        <attr name="windowContentTransitions" format="boolean" />
+
+        <!-- Reference to a TransitionManager XML resource defining the desired
+             transitions between different window content. -->
+        <attr name="windowContentTransitionManager" format="reference" />
+
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
@@ -1618,6 +1627,9 @@
         <attr name="windowCloseOnTouchOutside" />
         <attr name="windowTranslucentStatus" />
         <attr name="windowTranslucentNavigation" />
+        <attr name="windowContentTransitions" />
+        <attr name="windowContentTransitionManager" />
+
         <!-- The minimum width the window is allowed to be, along the major
              axis of the screen.  That is, when in landscape.  Can be either
              an absolute dimension or a fraction of the screen size in that
@@ -4675,6 +4687,14 @@
         <attr name="fromScene" format="reference" />
         <!-- The destination scene in this scene change. -->
         <attr name="toScene" format="reference" />
+        <!-- The name of the originating scene in this scene change.
+             Apps should treat this name as an API in the same sense
+             that an Intent action or extra key is. -->
+        <attr name="fromSceneName" format="string" />
+        <!-- The name of the destination scene in this scene change.
+             Apps should treat this name as an API in the same sense
+             that an Intent action or extra key is. -->
+        <attr name="toSceneName" format="string" />
     </declare-styleable>
 
     <!-- ========================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index db16e55..1604fc3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -591,8 +591,8 @@
     <!-- Disable lockscreen rotation by default -->
     <bool name="config_enableLockScreenRotation">false</bool>
 
-    <!-- Disable lockscreen translucent decor by default -->
-    <bool name="config_enableLockScreenTranslucentDecor">false</bool>
+    <!-- Enable lockscreen translucent decor by default -->
+    <bool name="config_enableLockScreenTranslucentDecor">true</bool>
 
     <!-- Enable translucent decor by default -->
     <bool name="config_enableTranslucentDecor">true</bool>
@@ -1182,6 +1182,22 @@
          where if the preferred is used we don't try the others. -->
     <bool name="config_dontPreferApn">false</bool>
 
+    <!-- The list of ril radio technologies (see ServiceState.java) which only support
+         a single data connection at one time.  This may change by carrier via
+         overlays (some don't support multiple pdp on UMTS).  All unlisted radio
+         tech types support unlimited types (practically only 2-4 used). -->
+    <integer-array name="config_onlySingleDcAllowed">
+        <item>4</item>  <!-- IS95A -->
+        <item>5</item>  <!-- IS95B -->
+        <item>6</item>  <!-- 1xRTT -->
+        <item>7</item>  <!-- EVDO_0 -->
+        <item>8</item>  <!-- EVDO_A -->
+        <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/public.xml b/core/res/res/values/public.xml
index dcaf6b3..090702d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2094,6 +2094,8 @@
 
   <public type="attr" name="fragmentBreadCrumbsStyle" />
   <public type="attr" name="fastScrollStyle" />
+  <public type="attr" name="windowContentTransitions" />
+  <public type="attr" name="windowContentTransitionManager" />
 
   <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
@@ -2105,4 +2107,6 @@
   <public type="style" name="Widget.DeviceDefault.FastScroll" />
   <public type="style" name="Widget.DeviceDefault.Light.FastScroll" />
 
+  <public type="style" name="Theme.Quantum" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a554407..d98d59a 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
@@ -4095,12 +4101,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>
 
@@ -4133,10 +4151,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/styles.xml b/core/res/res/values/styles.xml
index b1a86f8c..3af5d6d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -2408,6 +2408,16 @@
     <style name="Animation.Holo.Dialog" parent="Animation.Dialog">
     </style>
 
+    <style name="Animation.Quantum" parent="Animation.Holo">
+    </style>
+
+    <style name="Animation.Quantum.Activity" parent="Animation.Holo.Activity">
+        <item name="activityOpenEnterAnimation">@null</item>
+        <item name="activityOpenExitAnimation">@null</item>
+        <item name="activityCloseEnterAnimation">@null</item>
+        <item name="activityCloseExitAnimation">@anim/fade_out</item>
+    </style>
+
     <!-- Dialog styles -->
 
     <style name="AlertDialog.Holo" parent="AlertDialog">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 26a56a5..683d4f7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -284,6 +284,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" />
@@ -1092,7 +1093,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" />
@@ -1249,17 +1254,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" />
@@ -1431,6 +1436,7 @@
   <java-symbol type="array" name="config_locationProviderPackageNames" />
   <java-symbol type="array" name="config_defaultNotificationVibePattern" />
   <java-symbol type="array" name="config_notificationFallbackVibePattern" />
+  <java-symbol type="array" name="config_onlySingleDcAllowed" />
   <java-symbol type="bool" name="config_animateScreenLights" />
   <java-symbol type="bool" name="config_automatic_brightness_available" />
   <java-symbol type="bool" name="config_enableFusedLocationOverlay" />
@@ -1446,7 +1452,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" />
@@ -1589,8 +1594,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/values/themes.xml b/core/res/res/values/themes.xml
index b79f916c..0361df1 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -1068,7 +1068,7 @@
         <item name="presentationTheme">@android:style/Theme.Holo.Dialog.Presentation</item>
 
         <!-- Toast attributes -->
-        <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item>
+        <item name="toastFrameBackground">@android:drawable/toast_frame</item>
 
         <!-- Panel attributes -->
         <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_dark</item>
@@ -1397,7 +1397,7 @@
         <item name="presentationTheme">@android:style/Theme.Holo.Light.Dialog.Presentation</item>
 
         <!-- Toast attributes -->
-        <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item>
+        <item name="toastFrameBackground">@android:drawable/toast_frame</item>
 
         <!-- Panel attributes -->
         <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_light</item>
@@ -1925,4 +1925,11 @@
     <style name="Theme.Holo.Wallpaper.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
     </style>
+
+    <!-- Default Quantum Paper theme. -->
+    <style name="Theme.Quantum" parent="@android:style/Theme.Holo.Light">
+        <item name="android:windowContentTransitions">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Quantum.Activity</item>
+    </style>
+
 </resources>
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/keyboards/AVRCP.kl b/data/keyboards/AVRCP.kl
index 736b43c..4c91ece 100644
--- a/data/keyboards/AVRCP.kl
+++ b/data/keyboards/AVRCP.kl
@@ -14,8 +14,8 @@
 
 # Key layout used for Bluetooth AVRCP support.
 
-key 200   MEDIA_PLAY          WAKE
-key 201   MEDIA_PAUSE         WAKE
+key 200   MEDIA_PLAY_PAUSE    WAKE
+key 201   MEDIA_PLAY_PAUSE    WAKE
 key 166   MEDIA_STOP          WAKE
 key 163   MEDIA_NEXT          WAKE
 key 165   MEDIA_PREVIOUS      WAKE
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/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip
index 8668897..d3dd02a 100644
--- a/docs/downloads/training/BitmapFun.zip
+++ b/docs/downloads/training/BitmapFun.zip
Binary files differ
diff --git a/docs/downloads/training/OpenGLES.zip b/docs/downloads/training/OpenGLES.zip
index 862ae1f..5bdfee3 100644
--- a/docs/downloads/training/OpenGLES.zip
+++ b/docs/downloads/training/OpenGLES.zip
Binary files differ
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 1df2e22..bb34495 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on October 2, 2013.
+<p style="clear:both"><em>Data collected during a 7-day period ending on November 1, 2013.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -92,7 +92,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on October 2, 2013
+<p style="clear:both"><em>Data collected during a 7-day period ending on November 1, 2013
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -111,7 +111,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A0.2,99.8&chf=bg,s,00000000" />
+src="//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0|GL%203.0&chd=t%3A0.1,98.3,1.6&chf=bg,s,00000000" />
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -129,17 +129,21 @@
 </tr>
 <tr>
 <td>1.1 only</th>
-<td>0.2%</td>
+<td>0.1%</td>
 </tr>
 <tr>
-<td>2.0 &amp; 1.1</th>
-<td>99.8%</td>
+<td>2.0</th>
+<td>98.3%</td>
+</tr>
+<tr>
+<td>3.0</th>
+<td>1.6%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on October 2, 2013</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on November 1, 2013</em></p>
 
 
 
@@ -157,17 +161,17 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chs=500x250&cht=p&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A2.2%2C28.5%2C0.1%2C20.6%2C48.6&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean",
+    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean&chco=c4df9b%2C6fad0c&chd=t%3A1.7%2C26.3%2C0.1%2C19.8%2C52.1&chf=bg%2Cs%2C00000000&chs=500x250&cht=p",
     "data": [
       {
         "api": 8,
         "name": "Froyo",
-        "perc": "2.2"
+        "perc": "1.7"
       },
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "28.5"
+        "perc": "26.3"
       },
       {
         "api": 13,
@@ -177,22 +181,22 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "20.6"
+        "perc": "19.8"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "36.5"
+        "perc": "37.3"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "10.6"
+        "perc": "12.5"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "1.5"
+        "perc": "2.3"
       }
     ]
   }
@@ -209,19 +213,19 @@
       "Large": {
         "hdpi": "0.5",
         "ldpi": "0.6",
-        "mdpi": "3.5",
+        "mdpi": "3.6",
         "tvdpi": "1.2",
-        "xhdpi": "0.6"
+        "xhdpi": "0.5"
       },
       "Normal": {
-        "hdpi": "33.5",
+        "hdpi": "33.4",
         "ldpi": "0.1",
-        "mdpi": "15.3",
-        "xhdpi": "22.8",
-        "xxhdpi": "7.7"
+        "mdpi": "15.1",
+        "xhdpi": "22.2",
+        "xxhdpi": "8.8"
       },
       "Small": {
-        "ldpi": "9.4"
+        "ldpi": "9.2"
       },
       "Xlarge": {
         "hdpi": "0.3",
@@ -229,8 +233,8 @@
         "xhdpi": "0.1"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A10.1%2C23.3%2C1.2%2C34.3%2C23.5%2C7.7&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
-    "layoutchart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A4.8%2C6.4%2C79.5%2C9.4&chl=Xlarge%7CLarge%7CNormal%7CSmall"
+    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chco=c4df9b%2C6fad0c&chd=t%3A9.9%2C23.1%2C1.2%2C34.2%2C22.8%2C8.8&chf=bg%2Cs%2C00000000&chs=400x250&cht=p",
+    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chco=c4df9b%2C6fad0c&chd=t%3A4.8%2C6.4%2C79.6%2C9.2&chf=bg%2Cs%2C00000000&chs=400x250&cht=p"
   }
 ];
 
diff --git a/docs/html/about/versions/android-4.4.jd b/docs/html/about/versions/android-4.4.jd
index 6ef0337..42f257c 100644
--- a/docs/html/about/versions/android-4.4.jd
+++ b/docs/html/about/versions/android-4.4.jd
@@ -474,7 +474,7 @@
 
 <p>To provide batching, the {@link android.hardware.SensorManager} class adds two new versions of the {@link android.hardware.SensorManager#registerListener(SensorEventListener, Sensor, int, int) registerListener()} method that allow you to specify the "maximum report latency." This new parameter specifies the maximum delay that your {@link android.hardware.SensorEventListener} will tolerate for delivery of new sensor events. For example, if you specify a batch latency of one minute, the system will deliver the recent set of batched events at an interval no longer than one minute by making consecutive calls to your {@link android.hardware.SensorEventListener#onSensorChanged onSensorChanged()} method&mdash;once for each event that was batched. The sensor events will never be delayed longer than your maximum report latency value, but may arrive sooner if other apps have requested a shorter latency for the same sensor.</p>
 
-<p>However, be aware that the sensor will deliver your app the batched events based on your report latency <strong>only while the CPU is awake</strong>. Although a hardware sensor that supports batching will continue to collect sensor events while the CPU is asleep, it will not wake the CPU to deliver your app the batched events. When the sensor eventually runs out of its memory for events, it will begin dropping the oldest events in order to save the newest events. You can avoid losing events by waking the device before the sensor fills its memory then call {@link android.hardware.SensorManager#flush flush()} to capture the latest batch of events. To estimate when the memory will be full and should be flushed, call {@link android.hardware.Sensor#getFifoReservedEventCount()} to get the maximum number of sensor events it can save, and divide that number by the rate at which your app desires each event. Use that calculation to set wake alarms with {@link android.app.AlarmManager} that invoke your {@link android.app.Service} (which implements the {@link android.hardware.SensorEventListener}) to flush the sensor. It's okay that the alarm may execute even while the device is awake, because the alarm interval should be large enough that it occurs only a few times in a day.</p>
+<p>However, be aware that the sensor will deliver your app the batched events based on your report latency <strong>only while the CPU is awake</strong>. Although a hardware sensor that supports batching will continue to collect sensor events while the CPU is asleep, it will not wake the CPU to deliver your app the batched events. When the sensor eventually runs out of its memory for events, it will begin dropping the oldest events in order to save the newest events. You can avoid losing events by waking the device before the sensor fills its memory then call {@link android.hardware.SensorManager#flush flush()} to capture the latest batch of events. To estimate when the memory will be full and should be flushed, call {@link android.hardware.Sensor#getFifoMaxEventCount()} to get the maximum number of sensor events it can save, and divide that number by the rate at which your app desires each event. Use that calculation to set wake alarms with {@link android.app.AlarmManager} that invoke your {@link android.app.Service} (which implements the {@link android.hardware.SensorEventListener}) to flush the sensor.</p>
 
 
 <p class="note"><strong>Note:</strong> Not all devices support batching sensor events because it requires support by the hardware sensor. However, beginning with Android 4.4, you should always use the new {@link android.hardware.SensorManager#registerListener(SensorEventListener, Sensor, int, int) registerListener()} methods, because if the device does not support batching, then the system gracefully ignores the batch latency argument and delivers sensor events in real time.</p>
@@ -572,8 +572,8 @@
 
 
 
-<p style="margin-top:50px" class="note">For a detailed view of all API changes in Android 4.3, see the
-<a href="{@docRoot}sdk/api_diff/18/changes.html">API Differences Report</a>.</p>
+<p style="margin-top:50px" class="note">For a detailed view of all API changes in Android 4.4, see the
+<a href="{@docRoot}sdk/api_diff/19/changes.html">API Differences Report</a>.</p>
 
 
 
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index c7d1941..c6702b0 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -438,9 +438,9 @@
 
 <p>Android 4.3 also includes new utilities and APIs for creating better RTL
 strings and testing your localized UIs. A new <strong>BidiFormatter</strong>
-provides a set of simple APIs for wrapping Unicode strings so that you can
-fine-tune your text rendering in RTL scripts. To let you use this utility more
-broadly in your apps, the BidiFormatter APIs are also now available for earlier
+class provides a simple API for wrapping Unicode strings, so that RTL-script
+data is displayed as intended in LTR-locale messages and vice-versa. To let you use this utility more
+broadly in your apps, the BidiFormatter API is also now available for earlier
 platform versions through the Support Package in the Android SDK. </p>
 
 <p>To assist you with managing date formatting across locales, Android 4.3
diff --git a/docs/html/about/versions/kitkat.jd b/docs/html/about/versions/kitkat.jd
index 6c6cb6c..5e442ec 100644
--- a/docs/html/about/versions/kitkat.jd
+++ b/docs/html/about/versions/kitkat.jd
@@ -55,7 +55,7 @@
 <div id="44-android-44" class="version-section">
 
   <div style="padding:0px 0px 0px 60px;margin-top:-3px;float:right;">
-    <img src="{@docRoot}images/kk-android-44.png" alt="Android 4.4 on phone and tablet" width="380"> 
+    <img src="{@docRoot}design/media/index_landing_page.png" alt="Android 4.4 on phone and tablet" width="380">
   </div>
 
   <div class="landing-docs" style="float:right;clear:both;margin:22px 0 2em 3em;">
@@ -143,7 +143,8 @@
   lets you tune your app's behavior to match the device's memory configuration.
   You can modify or disable large-memory features as needed, depending on the
   use-cases you want to support on entry-level devices. Learn more about
-  optimizing your apps for low-memory devices <a href="">here</a>.
+  optimizing your apps for low-memory devices <a
+  href="{@docRoot}training/articles/memory.html">here</a>.
 </p>
 
 <p>
@@ -612,18 +613,20 @@
   Now it's easy to create high-quality video of your app, directly from your
   Android device. <span style="white-space:nowrap;">Android 4.4</span> adds
   support for screen recording and provides a <strong>screen recording
-  utility</strong> that lets you capture video as you use the device and store
-  it as an MP4 file. It's a great new way to create walkthroughs and tutorials
-  for your app, testing materials, marketing videos, and much more.
+  utility</strong> that lets you start and stop recording on a device that's
+  connected to your Android SDK environment over USB. It's a great new way to
+  create walkthroughs and tutorials for your app, testing materials, marketing
+  videos, and more.
 </p>
 
 <p>
-  You can record at any device-supported resolution and bitrate you want, and
-  the output retains the aspect ratio of the display. By default, the utility
-  selects a resolution equal or close to the device's display resolution in the
-  current orientation. When you are done recording, you can share the video
-  directly from your device or pull the MP4 file to your host computer for
-  post-production.
+  With the screen recording utility, you can capture video of your device screen
+  contents and store the video as an MP4 file on the device. You can record at any
+  device-supported resolution and bitrate you want, and the output retains the
+  aspect ratio of the display. By default, the utility selects a resolution
+  equal or close to the device's display resolution in the current orientation.
+  When you are done recording, you can share the video directly from your
+  device or pull the MP4 file to your host computer for post-production.
 </p>
 
 <p>
@@ -827,9 +830,7 @@
 
 <p>
   <span style="white-space:nowrap;">Android 4.4</span> upgrades its
-  SurfaceFlinger from OpenGL ES 1.0 to OpenGL ES 2.0. This boosts performance
-  by using multi-texturing, and it improves color calibration and supports more
-  advanced special effects.
+  SurfaceFlinger from OpenGL ES 1.0 to OpenGL ES 2.0.
 </p>
 
 <h4 id="44-composer">New Hardware Composer support for virtual displays</h4>
@@ -991,7 +992,7 @@
   <img src="{@docRoot}images/kk-pseudolocale-rtl.png" alt="" width="260" style=
   "margin-bottom:0;">
   <p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">
-    Pseudo-locales make it easier to test your app's localization.
+    The <strong>Force RTL layout</strong> option makes it easier to test your app's localization.
   </p>
 </div>
 
@@ -1002,18 +1003,19 @@
   files by using a new attribute.
 </p>
 
-<h4 id="44-pseudolocale-rtl">RTL pseudo-locale</h4>
+<h4 id="44-pseudolocale-rtl">Force RTL Layout</h4>
 
 <p>
-  To make it easier to test and debug your layouts, Android includes an RTL
-  pseudo-locale as a new developer option.
+  To make it easier to test and debug layout mirroring issues without switching
+  to an RTL language, Android includes a new developer option to force RTL layout
+  direction in all apps.
 </p>
 
 <p>
-  The RTL pseudo-locale switches the device to RTL layout for all locales and
+  The Force RTL layout option switches the device to RTL layout for all locales and
   displays text in your current language. This can help you find layout issues
   across your app, without having to display the app in an RTL language. You
-  can access the RTL pseudo-localed as in <strong>Settings &gt; Developer
+  can access the option in <strong>Settings &gt; Developer
   options &gt; Force RTL layout direction</strong>.
 </p>
 
diff --git a/docs/html/design/building-blocks/buttons.jd b/docs/html/design/building-blocks/buttons.jd
index 7957ef8..2a77e24 100644
--- a/docs/html/design/building-blocks/buttons.jd
+++ b/docs/html/design/building-blocks/buttons.jd
@@ -1,5 +1,5 @@
 page.title=Buttons
-page.tags="button","input"
+page.tags=button,input
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/controls/button.html">
@@ -9,39 +9,83 @@
   </div>
 </a>
 
-<p>A button consists of text and/or an image that clearly communicates what action will occur when the
-user touches it. Android supports two different types of buttons: <em>basic buttons</em> and <em>borderless
-buttons</em>. Both can contain text labels and/or images.</p>
+<p>A button consists of text and/or an image that clearly communicates what action
+  will occur when the user touches it. A button can have an image, text, or both.
+</p>
 
-<img src="{@docRoot}design/media/buttons_basic.png">
-
-<h2 id="basic">Basic Buttons</h2>
-
-<p>Basic buttons are traditional buttons with borders and background. Android supports two styles for
-basic buttons: default and small. Default buttons have slightly larger font size and are optimized
-for display outside of form content. Small buttons are intended for display alongside other content.
-They have a smaller font and smaller minimum height. Use small buttons in forms where they need to
-align with other UI elements.</p>
-
-<img src="{@docRoot}design/media/buttons_default_small.png">
-<div class="layout-content-row">
-  <div class="layout-content-col span-6">
-    <div class="figure-caption">
-      Default buttons in Holo Dark &amp; Light.
-    </div>
+<div class="layout-content-row" style="margin-top:22px">
+  <div class="layout-content-col span-3">
+    <img src="{@docRoot}design/media/icon_magnifying_glass.png" style="height:64px;padding:20px 0 0 40px;">
   </div>
-  <div class="layout-content-col span-6">
-    <div class="figure-caption">
-      Small buttons in Holo Dark &amp; Light.
-    </div>
+  <div class="layout-content-col span-3">
+    <img src="{@docRoot}design/media/buttons_text.png"  style="height:94px;">
+  </div>
+  <div class="layout-content-col span-7">
+    <img src="{@docRoot}design/media/buttons_image_and_text.png"  style="height:94px;">
   </div>
 </div>
 
-<h2 id="borderless">Borderless Buttons</h2>
+<div class="layout-content-row" style="margin-top:0;">
+  <div class="layout-content-col span-3">
+      <p>An image alone works best when the action can be represented by a symbol that's well understood.</p>
+  </div>
+  <div class="layout-content-col span-3">
+      <p>Text alone is most appropriate for actions that would be difficult to
+      represent visually, or are critical to convey in words to avoid any ambiguity.</p>
+  </div>
+  <div class="layout-content-col span-7">
+    <p>
+      Both an icon and text is most appropriate when they complement each other:
+      each carrying its own bit of information, but together making a larger whole.
+    </p>
 
-<p>Borderless buttons resemble basic buttons except that they have no borders or background. You can
-use borderless buttons with both icons and text. Borderless buttons are visually more lightweight
-than basic buttons and integrate nicely with other content.</p>
+    <p>
+      For example, in a birthday reminder card in Google Now, the button's text
+      describes the action while its image indicates that the action will be done
+      in Google+.
+    </p>
+  </div>
+</div>
 
-<img src="{@docRoot}design/media/buttons_borderless.png">
+<h3>What about button backgrounds?</h3>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <p>For <strong>image-only</strong> buttons, a background isn't necessary because
+    users are accustomed to interacting with objects.</p>
+
+    <div class="layout-content-row" style="margin-left:72px">
+      <div class="layout-content-col span-2">
+        <div class="do-dont-label bad emulate-content-left-padding" style="width:30px">Don't</div>
+        <img src="{@docRoot}design/media/buttons_image_bg_dont.png" style="padding-left:14px;">
+      </div>
+      <div class="layout-content-col span-2" style="width:29px;margin-left:10px;">
+        <div class="do-dont-label good"><strong>Do</strong></div>
+        <img src="{@docRoot}design/media/icon_alarm.png" style="width:31px;padding-top:7px;">
+      </div>
+    </div>
+  </div>
+
+<div class="layout-content-col span-7">
+<p>
+  For buttons <strong>with text</strong>, a background is also usually
+  unnecessary. To invite users to touch, phrase it as a clear action (e.g.
+  "Start", "Sign in") and use different color and formatting than the screen's
+  usual body text.
+</p>
+
+<p>
+  Use buttons with backgrounds sparingly. Because they have a heavy appearance,
+  they work best when there's only one or two of them on the screen. They're
+  most appropriate for:
+</p>
+
+<ul>
+  <li>A call to action you really want users to pursue (e.g. "Sign up")</li>
+  <li>A key decision point (e.g. "Accept" / "Decline")</li>
+  <li>When the user is about to commit a significant action (e.g. "Erase
+  everything", "Buy now")</li>
+</ul>
+</div>
+</div>
 
diff --git a/docs/html/design/building-blocks/dialogs.jd b/docs/html/design/building-blocks/dialogs.jd
index f4bb87e..f9897f4 100644
--- a/docs/html/design/building-blocks/dialogs.jd
+++ b/docs/html/design/building-blocks/dialogs.jd
@@ -1,5 +1,5 @@
 page.title=Dialogs
-page.tags="dialog","alert","popup","toast"
+page.tags=dialog,alert,popup,toast
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/dialogs.html">
diff --git a/docs/html/design/building-blocks/grid-lists.jd b/docs/html/design/building-blocks/grid-lists.jd
index 1a09ef5..cef7514 100644
--- a/docs/html/design/building-blocks/grid-lists.jd
+++ b/docs/html/design/building-blocks/grid-lists.jd
@@ -1,5 +1,5 @@
 page.title=Grid Lists
-page.tags="gridview","layout","listview"
+page.tags=gridview,layout,listview
 @jd:body
 
 <img src="{@docRoot}design/media/gridview_overview.png">
diff --git a/docs/html/design/building-blocks/lists.jd b/docs/html/design/building-blocks/lists.jd
index 5514824..54fa442 100644
--- a/docs/html/design/building-blocks/lists.jd
+++ b/docs/html/design/building-blocks/lists.jd
@@ -1,5 +1,5 @@
 page.title=Lists
-page.tags="listview","layout"
+page.tags=listview,layout
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/layout/listview.html">
diff --git a/docs/html/design/building-blocks/pickers.jd b/docs/html/design/building-blocks/pickers.jd
index 6dd72ba..860a126 100644
--- a/docs/html/design/building-blocks/pickers.jd
+++ b/docs/html/design/building-blocks/pickers.jd
@@ -1,5 +1,5 @@
 page.title=Pickers
-page.tags="datepicker","timepicker"
+page.tags=datepicker,timepicker
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/controls/pickers.html">
diff --git a/docs/html/design/building-blocks/progress.jd b/docs/html/design/building-blocks/progress.jd
index 90732f4..6946a75 100644
--- a/docs/html/design/building-blocks/progress.jd
+++ b/docs/html/design/building-blocks/progress.jd
@@ -1,5 +1,5 @@
 page.title=Progress &amp; Activity
-page.tags="progressbar","download","network"
+page.tags=progressbar,download,network
 @jd:body
 
 <p>Progress bars and activity indicators signal to users that something is happening that will take a moment.</p>
diff --git a/docs/html/design/building-blocks/scrolling.jd b/docs/html/design/building-blocks/scrolling.jd
index 13b3b09..41e7cec 100644
--- a/docs/html/design/building-blocks/scrolling.jd
+++ b/docs/html/design/building-blocks/scrolling.jd
@@ -1,5 +1,5 @@
 page.title=Scrolling
-page.tags="scrollview","listview"
+page.tags=scrollview,listview
 @jd:body
 
 <p>Scrolling allows the user to navigate to content in the overflow using a swipe gesture. The
diff --git a/docs/html/design/building-blocks/seek-bars.jd b/docs/html/design/building-blocks/seek-bars.jd
index 9d38e36..1465688 100644
--- a/docs/html/design/building-blocks/seek-bars.jd
+++ b/docs/html/design/building-blocks/seek-bars.jd
@@ -1,5 +1,5 @@
 page.title=Seek Bars and Sliders
-page.tags="seekbar","progressbar"
+page.tags=seekbar,progressbar
 @jd:body
 
 <p>Interactive sliders make it possible to select a value from a continuous or discrete range of values
diff --git a/docs/html/design/building-blocks/spinners.jd b/docs/html/design/building-blocks/spinners.jd
index c00b639..f8d92d4 100644
--- a/docs/html/design/building-blocks/spinners.jd
+++ b/docs/html/design/building-blocks/spinners.jd
@@ -1,5 +1,5 @@
 page.title=Spinners
-page.tags="spinner","dropdown"
+page.tags=spinner,dropdown
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/controls/spinner.html">
diff --git a/docs/html/design/building-blocks/switches.jd b/docs/html/design/building-blocks/switches.jd
index 74cab5a..b294689 100644
--- a/docs/html/design/building-blocks/switches.jd
+++ b/docs/html/design/building-blocks/switches.jd
@@ -1,5 +1,5 @@
 page.title=Switches
-page.tags="switch","checkbox","radiobutton","button"
+page.tags=switch,checkbox,radiobutton,button
 @jd:body
 
 <p>Switches allow the user to select options. There are three kinds of switches: checkboxes, radio
diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
index 5a5da5d8..1fa3461 100644
--- a/docs/html/design/building-blocks/tabs.jd
+++ b/docs/html/design/building-blocks/tabs.jd
@@ -1,5 +1,5 @@
 page.title=Tabs
-page.tags="tabs","actionbar","navigation","viewpager"
+page.tags=tabs,actionbar,navigation,viewpager
 @jd:body
 
 <img src="{@docRoot}design/media/tabs_overview.png">
diff --git a/docs/html/design/building-blocks/text-fields.jd b/docs/html/design/building-blocks/text-fields.jd
index 383531b..4545bfb 100644
--- a/docs/html/design/building-blocks/text-fields.jd
+++ b/docs/html/design/building-blocks/text-fields.jd
@@ -1,5 +1,5 @@
 page.title=Text Fields
-page.tags="text","edittext","input"
+page.tags=text,edittext,input
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/controls/text.html">
diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd
index d514c14..ddeda5c 100644
--- a/docs/html/design/downloads/index.jd
+++ b/docs/html/design/downloads/index.jd
@@ -1,4 +1,5 @@
 page.title=Downloads
+page.tags=Icons,stencils,color swatches
 @jd:body
 
 <div class="layout-content-row">
@@ -15,7 +16,7 @@
 
 <p>
   <a class="download-button" onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'All Design Assets']);"
-    href="{@docRoot}downloads/design/Android_Design_Downloads_20130814.zip">Download All</a>
+    href="{@docRoot}downloads/design/Android_Design_Downloads_20131106.zip">Download All</a>
 </p>
 
   </div>
@@ -26,8 +27,8 @@
 <div class="layout-content-row">
   <div class="layout-content-col span-5">
 
-<p>Drag and drop your way to beautifully designed Ice Cream Sandwich apps. The stencils feature the
-rich typography, colors, interactive controls, and icons found throughout Android 4.0, along with
+<p>Drag and drop your way to beautifully designed Android apps. The stencils feature the
+rich typography, colors, interactive controls, and icons found throughout Android, along with
 phone and tablet outlines to frame your creations. Source files for icons and controls are also
 available.</p>
 
@@ -40,14 +41,14 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Fireworks Stencil']);"
+  <!--<a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Fireworks Stencil']);"
     href="{@docRoot}downloads/design/Android_Design_Fireworks_Stencil_20120814.png">Adobe&reg; Fireworks&reg; PNG Stencil</a>
   <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Illustrator Stencil']);"
     href="{@docRoot}downloads/design/Android_Design_Illustrator_Vectors_20120814.ai">Adobe&reg; Illustrator&reg; Stencil</a>
   <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'OmniGraffle Stencil']);"
-    href="{@docRoot}downloads/design/Android_Design_OmniGraffle_Stencil_20120814.graffle">Omni&reg; OmniGraffle&reg; Stencil</a>
+    href="{@docRoot}downloads/design/Android_Design_OmniGraffle_Stencil_20120814.graffle">Omni&reg; OmniGraffle&reg; Stencil</a>-->
   <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Photoshop Sources']);"
-    href="{@docRoot}downloads/design/Android_Design_Holo_Widgets_20120814.zip">Adobe&reg; Photoshop&reg; Sources</a>
+    href="{@docRoot}downloads/design/Android_Design_Stencils_Sources_20131106.zip">Adobe&reg; Photoshop&reg; Stencils and Sources</a>
 </p>
 
   </div>
@@ -74,7 +75,7 @@
 
 <p>
   <a class="download-button"  onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Action Bar Icons']);"
-    href="{@docRoot}downloads/design/Android_Design_Icons_20130926.zip">Action Bar Icon Pack</a>
+    href="{@docRoot}downloads/design/Android_Design_Icons_20131106.zip">Action Bar Icon Pack</a>
 </p>
 
   </div>
@@ -114,7 +115,7 @@
   <div class="layout-content-col span-5">
 
 <h4>Color</h4>
-<p>Blue is the standard accent color in Android's color palette. Each color has a corresponding darker
+<p>In Android's color palette, each color has a corresponding darker
 shade that can be used as a complement when needed.</p>
 <p><a href="{@docRoot}design/style/color.html">More on Color</a></p>
 
diff --git a/docs/html/design/media/buttons_image_and_text.png b/docs/html/design/media/buttons_image_and_text.png
new file mode 100644
index 0000000..b7ffccb
--- /dev/null
+++ b/docs/html/design/media/buttons_image_and_text.png
Binary files differ
diff --git a/docs/html/design/media/buttons_image_bg_dont.png b/docs/html/design/media/buttons_image_bg_dont.png
new file mode 100644
index 0000000..651d3ce
--- /dev/null
+++ b/docs/html/design/media/buttons_image_bg_dont.png
Binary files differ
diff --git a/docs/html/design/media/buttons_text.png b/docs/html/design/media/buttons_text.png
new file mode 100644
index 0000000..54d3dd3
--- /dev/null
+++ b/docs/html/design/media/buttons_text.png
Binary files differ
diff --git a/docs/html/design/media/calendar.mp4 b/docs/html/design/media/calendar.mp4
deleted file mode 100644
index cdd72d2..0000000
--- a/docs/html/design/media/calendar.mp4
+++ /dev/null
Binary files differ
diff --git a/docs/html/design/media/calendar.ogv b/docs/html/design/media/calendar.ogv
deleted file mode 100644
index efb23d2..0000000
--- a/docs/html/design/media/calendar.ogv
+++ /dev/null
Binary files differ
diff --git a/docs/html/design/media/calendar.webm b/docs/html/design/media/calendar.webm
deleted file mode 100644
index 9d7d9f2..0000000
--- a/docs/html/design/media/calendar.webm
+++ /dev/null
Binary files differ
diff --git a/docs/html/design/media/dialogs_popups_example.png b/docs/html/design/media/dialogs_popups_example.png
index 6c98b1f..a8ebacd 100644
--- a/docs/html/design/media/dialogs_popups_example.png
+++ b/docs/html/design/media/dialogs_popups_example.png
Binary files differ
diff --git a/docs/html/design/media/icon_alarm.png b/docs/html/design/media/icon_alarm.png
new file mode 100644
index 0000000..36ce643a
--- /dev/null
+++ b/docs/html/design/media/icon_alarm.png
Binary files differ
diff --git a/docs/html/design/media/icon_magnifying_glass.png b/docs/html/design/media/icon_magnifying_glass.png
new file mode 100644
index 0000000..d443a85
--- /dev/null
+++ b/docs/html/design/media/icon_magnifying_glass.png
Binary files differ
diff --git a/docs/html/design/media/multipane_view_tablet.png b/docs/html/design/media/multipane_view_tablet.png
index d59308a..a713591 100644
--- a/docs/html/design/media/multipane_view_tablet.png
+++ b/docs/html/design/media/multipane_view_tablet.png
Binary files differ
diff --git a/docs/html/design/media/navigation_between_apps_back.png b/docs/html/design/media/navigation_between_apps_back.png
index a817374..d0c12cf 100644
--- a/docs/html/design/media/navigation_between_apps_back.png
+++ b/docs/html/design/media/navigation_between_apps_back.png
Binary files differ
diff --git a/docs/html/design/media/navigation_between_apps_inward.png b/docs/html/design/media/navigation_between_apps_inward.png
index 321d0da..75e7fc6 100644
--- a/docs/html/design/media/navigation_between_apps_inward.png
+++ b/docs/html/design/media/navigation_between_apps_inward.png
Binary files differ
diff --git a/docs/html/design/media/navigation_between_apps_up.png b/docs/html/design/media/navigation_between_apps_up.png
index 42d0d8f..67ebb77 100644
--- a/docs/html/design/media/navigation_between_apps_up.png
+++ b/docs/html/design/media/navigation_between_apps_up.png
Binary files differ
diff --git a/docs/html/design/media/navigation_from_outside_back.png b/docs/html/design/media/navigation_from_outside_back.png
index 0e1aa04..9153b08 100644
--- a/docs/html/design/media/navigation_from_outside_back.png
+++ b/docs/html/design/media/navigation_from_outside_back.png
Binary files differ
diff --git a/docs/html/design/media/navigation_up_vs_back_gmail.png b/docs/html/design/media/navigation_up_vs_back_gmail.png
index d5eaa18..7cc295e 100644
--- a/docs/html/design/media/navigation_up_vs_back_gmail.png
+++ b/docs/html/design/media/navigation_up_vs_back_gmail.png
Binary files differ
diff --git a/docs/html/design/media/touch_feedback.mp4 b/docs/html/design/media/touch_feedback.mp4
new file mode 100644
index 0000000..b91dc4b
--- /dev/null
+++ b/docs/html/design/media/touch_feedback.mp4
Binary files differ
diff --git a/docs/html/design/media/touch_feedback.ogv b/docs/html/design/media/touch_feedback.ogv
new file mode 100644
index 0000000..22c9f97
--- /dev/null
+++ b/docs/html/design/media/touch_feedback.ogv
Binary files differ
diff --git a/docs/html/design/media/touch_feedback.webm b/docs/html/design/media/touch_feedback.webm
new file mode 100644
index 0000000..a65c142
--- /dev/null
+++ b/docs/html/design/media/touch_feedback.webm
Binary files differ
diff --git a/docs/html/design/media/touch_feedback_thumb.png b/docs/html/design/media/touch_feedback_thumb.png
new file mode 100644
index 0000000..49af69f
--- /dev/null
+++ b/docs/html/design/media/touch_feedback_thumb.png
Binary files differ
diff --git a/docs/html/design/media/widgets_gestures.png b/docs/html/design/media/widgets_gestures.png
index 5e1268d..bbce87d 100644
--- a/docs/html/design/media/widgets_gestures.png
+++ b/docs/html/design/media/widgets_gestures.png
Binary files differ
diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
index 532900e..50c82fe 100644
--- a/docs/html/design/patterns/accessibility.jd
+++ b/docs/html/design/patterns/accessibility.jd
@@ -1,5 +1,5 @@
 page.title=Accessibility
-page.tags="accessibility","navigation","input"
+page.tags=accessibility,navigation,input
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}training/accessibility/index.html">
@@ -86,4 +86,4 @@
   <li>Provide alternatives to affordances that time out</li>
   <li>Use standard framework controls or enable TalkBack for custom controls</li>
   <li>Try it out yourself</li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index 939370c..f0104b5 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -1,5 +1,5 @@
 page.title=Action Bar
-page.tags="actionbar","navigation"
+page.tags=actionbar,navigation
 @jd:body
 
 <img src="{@docRoot}design/media/action_bar_pattern_overview.png">
@@ -182,7 +182,7 @@
 <p>
 
 <a onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Action Bar Icons (@actionbar page)']);"
-   href="{@docRoot}downloads/design/Android_Design_Icons_20130926.zip">Download the Action Bar Icon Pack</a>
+   href="{@docRoot}downloads/design/Android_Design_Icons_20131106.zip">Download the Action Bar Icon Pack</a>
 
 </p>
 
@@ -277,4 +277,4 @@
 <p>Sometimes it is important to display contextual information for your app that's always visible.
 Examples are the number of unread messages in a messaging inbox view or the Now Playing information
 in a music player. Carefully plan which important information you would like to display and
-structure your action bars accordingly.</p>
\ No newline at end of file
+structure your action bars accordingly.</p>
diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
index 1447d4e..e0a11ed 100644
--- a/docs/html/design/patterns/app-structure.jd
+++ b/docs/html/design/patterns/app-structure.jd
@@ -1,5 +1,5 @@
 page.title=App Structure
-page.tags="navigation","layout","tablet"
+page.tags=navigation,layout,tablet
 @jd:body
 
     <p>Apps come in many varieties that address very different needs. For example:</p>
@@ -307,4 +307,4 @@
 <li>
 <p>Allow for quick navigation between detail items with swipe views.</p>
 </li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/docs/html/design/patterns/buttons.jd b/docs/html/design/patterns/buttons.jd
new file mode 100644
index 0000000..2d65b2d
--- /dev/null
+++ b/docs/html/design/patterns/buttons.jd
@@ -0,0 +1,151 @@
+page.title=Buttons
+page.tags=buttons
+@jd:body
+
+<p>
+  Some content is best experienced full screen, like videos, games, image
+  galleries, books, and slides in a presentation. You can engage users more
+  deeply with content in full screen by minimizing visual distraction from app
+  controls and protecting users from escaping the app accidentally.
+</p>
+
+<div style="margin:auto;padding:auto;text-align:center;">
+    <img src="{@docRoot}design/media/fullscreen_landing.png" style="margin:1em auto 2em auto;">
+</div>
+<p>
+  In version 4.4, Android offers two approaches for making your app go full
+  screen: Lean Back and Immersive. In both approaches, all persistent system
+  bars are hidden. The difference between them is how the user brings the bars
+  back into view.
+</p>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <h4>Lean Back</h4>
+    <p>Touch the screen anywhere to bring back system bars. </p>
+    <img src="{@docRoot}design/media/fullscreen_leanback.png" style="width:311px;">
+  </div>
+  <div class="layout-content-col span-6">
+    <h4>Immersive</h4>
+    <p>Swipe from the any edge of the screen with a hidden bar to bring back system bars. </p>
+    <img src="{@docRoot}design/media/fullscreen_immersive_swipe_bottom.png" style="width:160px;float:right">
+    <img src="{@docRoot}design/media/fullscreen_immersive_swipe_top.png" style="width:160px">
+  </div>
+</div>
+
+<h2 id="leanback">
+  Lean Back
+</h2>
+
+<p>
+  The Lean Back approach is for full-screen experiences in which users won't be
+  interacting heavily with the screen while consuming content, like while
+  watching a video.
+</p>
+
+<p>
+  In this type of experience, users are leaning back and watching the screen.
+  Then, when they need to bring back the bars, they simply touch anywhere. This
+  gesture is easy and intuitive.
+</p>
+
+    <img src="{@docRoot}design/media/fullscreen_leanback.png" style="width:311px;">
+
+<h2 id="immersive">
+  Immersive
+</h2>
+
+<p>
+  The Immersive approach is mainly intended for apps in which the user will be
+  heavily interacting with the full screen as part of the primary experience.
+  Examples are games, viewing images in a gallery, or reading paginated
+  content, like a book or slides in a presentation.
+</p>
+
+<p>
+  In this type of experience, when users need to bring back the system bars,
+  they swipe from any edge where a system bar is hidden. By requiring this more
+  deliberate gesture, the user's deep engagement with your app won't be
+  interrupted by accidental touches and swipes.
+</p>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/fullscreen_immersive_swipe_bottom.png" style="width:160px;float:right">
+    <img src="{@docRoot}design/media/fullscreen_immersive_swipe_top.png" style="width:160px">
+  </div>
+</div>
+
+<p>
+  The user learns about the gesture to bring back the system bars through a
+  message that appears the first time the app goes full screen.
+</p>
+
+<p>
+  If your app has its own controls that aren't needed when a user is immersed
+  in content, make them disappear and reappear in sync with the system bars.
+  This rule also applies to any app-specific gestures you might have for hiding
+  and showing app controls. For example, if touching anywhere on the screen
+  toggles the appearance of an action bar or a palette, then it must also
+  toggle the appearance of system bars.
+</p>
+
+<p>
+  You might be tempted to use this approach just to maximize screen real
+  estate. But be mindful of how often users jump in and out of apps to check
+  notifications, do impromptu searches, and more. This approach will cause
+  users to lose easy access to system navigation, so a little extra space
+  should not be the only benefit they're getting in return.
+</p>
+
+<h2 id="variation_using_edges">
+  Variation: Swiping from edges with bars also affects the app
+</h2>
+
+<p>
+  In the Immersive approach, any time a user swipes from an edge with a system
+  bar, the Android framework takes care of revealing the system bars. Your app
+  won't even be aware that this gesture occurred.
+</p>
+
+<p>
+  But in some apps, the user might occasionally need to swipe from the edge as
+  <strong>part of the primary app experience</strong>. Examples are games and
+  drawing applications.
+</p>
+
+<p>
+  For apps with this requirement, you can use a variation on the Immersive
+  approach: when a user swipes from an edge with a system bar, system bars are
+  shown and the gesture is passed to the app so the app can respond to the
+  gesture.
+</p>
+
+<p>
+  For example, in a drawing app that uses this approach, if a user wants to
+  draw a line that begins at the very edge of the screen, swiping from the edge
+  would reveal the system bars and also start drawing a line that begins at the
+  very edge.
+</p>
+
+<p>
+  In this approach, to minimize disruption while a user is deeply engaged in
+  the app, the system bars are semi-transparent. The bars automatically
+  disappear after a few seconds of no interaction or as soon as the user
+  touches or gestures anywhere outside the system bars.
+</p>
+
+<h2 id="lightsout">What About Lights Out Mode?</h2>
+
+<p>
+  Before Android 4.4, the design guideline was to use Lights Out mode, a mode
+  in which the Action Bar and Status Bar fades away and becomes unavailable
+  after a few seconds of inactivity. The Navigation Bar is still available and
+  responds to touches but appears dimmed.
+</p>
+
+<p>
+  Replace previous implementations of Lights Out mode with the Lean Back or
+  Immersive approaches. Continue to use Lights Out mode for implementations of
+  your app targeted for earlier releases.
+</p>
diff --git a/docs/html/design/patterns/compatibility.jd b/docs/html/design/patterns/compatibility.jd
index 5ca6d8b..5a1562c 100644
--- a/docs/html/design/patterns/compatibility.jd
+++ b/docs/html/design/patterns/compatibility.jd
@@ -1,5 +1,5 @@
 page.title=Backwards Compatibility
-page.tags="support"
+page.tags=support
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}training/basics/supporting-devices/index.html">
diff --git a/docs/html/design/patterns/confirming-acknowledging.jd b/docs/html/design/patterns/confirming-acknowledging.jd
index e347231..d39d32d 100644
--- a/docs/html/design/patterns/confirming-acknowledging.jd
+++ b/docs/html/design/patterns/confirming-acknowledging.jd
@@ -1,5 +1,5 @@
 page.title=Confirming &amp; Acknowledging
-page.tags="dialog","toast","notification"
+page.tags=dialog,toast,notification
 @jd:body
 
 <p>In some situations, when a user invokes an action in your app, it's a good idea to <em>confirm</em> or <em>acknowledge</em> that action through text.</p>
@@ -67,4 +67,4 @@
     <p><strong>Acknowledgment is unnecessary</strong>. The user will know the app is gone from the Home Screen because they made it disappear by dragging it away.</p>
 
   </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/design/patterns/fullscreen.jd b/docs/html/design/patterns/fullscreen.jd
index 191ca40..624d44c 100644
--- a/docs/html/design/patterns/fullscreen.jd
+++ b/docs/html/design/patterns/fullscreen.jd
@@ -1,5 +1,5 @@
 page.title=Full Screen
-page.tags="full screen","immersive", "leanback"
+page.tags=full screen,immersive,leanback
 @jd:body
 
 <p>
@@ -9,8 +9,9 @@
   controls and protecting users from escaping the app accidentally.
 </p>
 
+<div style="margin:auto;padding:auto;text-align:center;">
     <img src="{@docRoot}design/media/fullscreen_landing.png" style="margin:1em auto 2em auto;">
-
+</div>
 <p>
   In version 4.4, Android offers two approaches for making your app go full
   screen: Lean Back and Immersive. In both approaches, all persistent system
@@ -147,4 +148,4 @@
   Replace previous implementations of Lights Out mode with the Lean Back or
   Immersive approaches. Continue to use Lights Out mode for implementations of
   your app targeted for earlier releases.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/design/patterns/gestures.jd b/docs/html/design/patterns/gestures.jd
index 837a6dd..1ec7094 100644
--- a/docs/html/design/patterns/gestures.jd
+++ b/docs/html/design/patterns/gestures.jd
@@ -1,5 +1,5 @@
 page.title=Gestures
-page.tags="gesture","input","touch"
+page.tags=gesture,input,touch
 @jd:body
 
 <p>Gestures allow users to interact with your app by manipulating the screen objects you provide. The
@@ -65,8 +65,9 @@
   <div class="layout-content-col span-4">
     <img src="{@docRoot}design/media/gesture_doubletouch.png">
     <h4>Double touch </h4>
-    <p>Scales up the smallest targetable view, if available, or scales a standard amount
-      around the gesture. Also used as a secondary gesture for text selection.</p>
+    <p> Scales up a standard amount around the target with each repeated gesture until reaching
+    maximum scale. For nested views, scales up the smallest targetable view, or returns it to
+    its original scale. Also used as a secondary gesture for text selection.</p>
     <ul>
       <li class="no-bullet with-icon action">
         <h4>Action</h4>
diff --git a/docs/html/design/patterns/help.jd b/docs/html/design/patterns/help.jd
index ad5742d..bf708b1 100644
--- a/docs/html/design/patterns/help.jd
+++ b/docs/html/design/patterns/help.jd
@@ -1,5 +1,5 @@
 page.title=Help
-page.tags="settings","preferences"
+page.tags=settings,preferences
 @jd:body
 
 <p>We wish we could guarantee that if you follow every piece of advice on this website, everyone will be able to learn and use your app without a hitch. Sadly, that's not the case.</p>
@@ -110,4 +110,4 @@
 <p>People don't read help from start to finish. They scan around, looking for a piece of information containing the answer they need. Make it less burdensome with friendly formatting and layout choices like bold headings, bulleted and numbered lists, tables, and white space between paragraphs. And if you have a large amount of content, divide it into multiple screens to cut down on scrolling.</p>
 
 <h4>Take me straight to the answer</h4>
-<p>What's better than a screen that's easy to scan? A screen that requires no scanning at all because the answer's right there. Consider having each screen in your app navigate to help that's relevant just to that screen. We call this <em>contextual help</em>, and it's the holy grail of user assistance. If you take this approach, be sure to also provide a way to get to the rest of the help content.</p>
\ No newline at end of file
+<p>What's better than a screen that's easy to scan? A screen that requires no scanning at all because the answer's right there. Consider having each screen in your app navigate to help that's relevant just to that screen. We call this <em>contextual help</em>, and it's the holy grail of user assistance. If you take this approach, be sure to also provide a way to get to the rest of the help content.</p>
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index 06c8189..ff2dd4e 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,5 +1,5 @@
 page.title=Multi-pane Layouts
-page.tags="tablet","navigation","layout","fragment"
+page.tags=tablet,navigation,layout,fragment
 @jd:body
 
 
diff --git a/docs/html/design/patterns/navigation-drawer.jd b/docs/html/design/patterns/navigation-drawer.jd
index bf6609e..7e63ba6c 100644
--- a/docs/html/design/patterns/navigation-drawer.jd
+++ b/docs/html/design/patterns/navigation-drawer.jd
@@ -1,5 +1,5 @@
 page.title=Navigation Drawer
-page.tags="DrawerLayout","SlidingPaneLayout"
+page.tags=DrawerLayout,SlidingPaneLayout
 @jd:body
 
 
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 6f2215a..08828e8 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,5 +1,5 @@
 page.title=Navigation with Back and Up
-page.tags="navigation","activity","task","up navigation","back navigation"
+page.tags=navigation,activity,task,up navigation,back navigation
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
diff --git a/docs/html/design/patterns/new.jd b/docs/html/design/patterns/new.jd
index 50cb950..d672e46 100644
--- a/docs/html/design/patterns/new.jd
+++ b/docs/html/design/patterns/new.jd
@@ -1,5 +1,5 @@
 page.title=New in Android
-page.tags="KitKat", "Android 4.4"
+page.tags=KitKat,Android 4.4
 @jd:body
 
 
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index 973ffde..ee46795 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -1,5 +1,5 @@
 page.title=Selection
-page.tags="actionmode","navigation","contextual"
+page.tags=actionmode,navigation,contextual
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/menus.html#context-menu">
diff --git a/docs/html/design/patterns/settings.jd b/docs/html/design/patterns/settings.jd
index fa3e538..a09193d 100644
--- a/docs/html/design/patterns/settings.jd
+++ b/docs/html/design/patterns/settings.jd
@@ -1,5 +1,5 @@
 page.title=Settings
-page.tags="preferences","sharedpreferences"
+page.tags=preferences,sharedpreferences
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/ui/settings.html">
@@ -696,4 +696,4 @@
 <li><p>Use design patterns wherever applicable so users don't face a learning curve.</p></li>
 <li><p>Choose defaults that are safe, neutral, and fit the majority of users.</p></li>
 <li><p>Give each setting a clear, concise label and use secondary text appropriately.</p></li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/docs/html/design/patterns/swipe-views.jd b/docs/html/design/patterns/swipe-views.jd
index 4c9fb88..89397ae 100644
--- a/docs/html/design/patterns/swipe-views.jd
+++ b/docs/html/design/patterns/swipe-views.jd
@@ -1,5 +1,5 @@
 page.title=Swipe Views
-page.tags="viewpager","navigation","tabs"
+page.tags=viewpager,navigation,tabs
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}training/implementing-navigation/lateral.html">
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index 87ebbb9..953c125 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -1,5 +1,5 @@
 page.title=Widgets
-page.tags="appwidget","home"
+page.tags=appwidget,home
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/appwidgets/index.html">
diff --git a/docs/html/design/style/branding.jd b/docs/html/design/style/branding.jd
index 9ef934d..2353a93 100644
--- a/docs/html/design/style/branding.jd
+++ b/docs/html/design/style/branding.jd
@@ -1,5 +1,5 @@
 page.title=Your Branding
-page.tags="branding","logo"
+page.tags=branding,logo
 @jd:body
 
 <p>Following Android design patterns doesn't mean that your app has to look the same as
@@ -49,16 +49,16 @@
 <div class="vspace size-1">&nbsp;</div>
 
 <div class="layout-content-row">
-  <div class="layout-content-col span-6">
-        <img src="{@docRoot}design/media/yourbranding_icon.png" style="width:60px;float:left;padding-right:1em;">
-    <div class="figure-caption" style="widdth:220px;margin-left:20px;">
-    The HowzAbout app uses a launcher icon that is a shortened version of its full logo.
+  <div class="layout-content-col span-6" style="padding-top:24px;">
+        <img src="{@docRoot}design/media/branding_launcher_icon.png" style="width:60px;float:left;padding-right:1em;">
+    <div class="figure-caption" style="width:290px;margin-left:20px;">
+    Google+ reinforces its brand by carrying its launcher icon through to the action bar.
     </div>
-
+        <img src="{@docRoot}design/media/branding_logo_icon_action_bar.png" style="width:320px;float:left;padding-right:1em;">
   </div>
   <div class="layout-content-col span-6">
-    <img src="{@docRoot}design/media/yourbranding_app.png" style="width:94%">
-    <div class="figure-caption">
+    <img src="{@docRoot}design/media/yourbranding_app.png" style="width:320px;">
+    <div class="figure-caption" style="width:320px;">
       Example of a the logo in the action bar. This works well in cases where the brand's logo matches the name of the app.
     </div>
   </div>
@@ -77,7 +77,7 @@
   </div>
 
   <div class="layout-content-col span-6">
-    <img src="{@docRoot}design/media/yourbranding_in-app-icons.png" style="width:300px;margin:12px 48px 0 16px;"">
+    <img src="{@docRoot}design/media/yourbranding_in-app-icons.png" style="width:300px;margin:12px 48px 0 16px;">
     </div>
   </div>
 </div>
@@ -100,9 +100,9 @@
 
     <div style="margin-bottom:1em;">
       <span class="do-dont-label bad" style="margin-left:12px">Don't</span>
-      <span style="margin-left: 44px;"  class="do-dont-label good"><strong>Do</strong></span>
+      <span style="margin-left: 64px;"  class="do-dont-label good"><strong>Do</strong></span>
     </div>
-      <img src="{@docRoot}design/media/yourbranding_sharing.png" style="width:200px;">
+      <img src="{@docRoot}design/media/yourbranding_sharing.png" style="width:180px;">
   </div>
 </div>
 
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index b0a3439..5dde600 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -1,5 +1,5 @@
 page.title=Iconography
-page.tags="icons"
+page.tags=icons
 @jd:body
 
 <img src="{@docRoot}design/media/iconography_overview.png">
@@ -139,7 +139,7 @@
 </p>
 <p>
 <a onClick="_gaq.push(['_trackEvent', 'Design', 'Download', 'Action Bar Icons (@iconography page)']);"
-   href="{@docRoot}downloads/design/Android_Design_Icons_20130926.zip">Download the Action Bar Icon Pack</a>
+   href="{@docRoot}downloads/design/Android_Design_Icons_20131106.zip">Download the Action Bar Icon Pack</a>
 </p>
 
 <div class="layout-content-row">
diff --git a/docs/html/design/style/metrics-grids.jd b/docs/html/design/style/metrics-grids.jd
index c375631..a553475 100644
--- a/docs/html/design/style/metrics-grids.jd
+++ b/docs/html/design/style/metrics-grids.jd
@@ -1,5 +1,5 @@
 page.title=Metrics and Grids
-page.tags="layout","screens"
+page.tags=layout,screens
 @jd:body
 
 <p>Devices vary not only in physical size, but also in screen density (<acronym title="Dots per
diff --git a/docs/html/design/style/touch-feedback.jd b/docs/html/design/style/touch-feedback.jd
index a5bf7b3..9f36fed 100644
--- a/docs/html/design/style/touch-feedback.jd
+++ b/docs/html/design/style/touch-feedback.jd
@@ -1,5 +1,5 @@
 page.title=Touch Feedback
-page.tags="input","button"
+page.tags=input,button
 @jd:body
 
     <div class="layout-content-row" style="margin-bottom: -100px">
@@ -7,8 +7,6 @@
 
 <p>Use illumination and dimming to respond to touches, reinforce the resulting behaviors
 of gestures, and indicate what actions are enabled and disabled.</p>
-<p>Whenever a user touches an actionable area in your app, provide a subtle visual response.
-This lets the user know which object was touched and that your app is "listening".</p>
 
 <p><strong>Be responsive to touches in a gentle way</strong>. Whenever a user touches an
 actionable area in your app, let them know the app is "listening" by providing a visual
@@ -22,27 +20,16 @@
 easier because the default touch feedback works with whatever hue you choose.</li>
 </ul>
 
-  </div>
+</div>
 
-  <div class="layout-content-col span-6" style="float:right;">
-
-   <!-- <div class="framed-nexus5-port-span-5">
-      <video class="play-on-hover" autoplay>
-        <source src="{@docRoot}design/media/calendar.mp4" type="video/mp4">
-        <source src="{@docRoot}design/media/calendar.webm" type="video/webm">
-        <source src="{@docRoot}design/media/calendar.ogv" type="video/ogg">
-      </video>
-    </div>
-    <div class="figure-caption" style="margin-top:0">
-      <div class="video-instructions">&nbsp;</div>
-    </div>
-  </div> -->
-
-
-  <div class="layout-content-col span-6">
-
-    <img src="{@docRoot}design/media/touch_feedback_reaction_response.png">
-
+<div class="layout-content-col span-6" style="float:right;">
+  <video  class="play-on-hover" width="268" height="442" autoplay style="border:1px solid #ddd;background-color:#f9f9f9;" poster="">
+    <source src="{@docRoot}design/media/touch_feedback.mp4" type="video/mp4">
+    <source src="{@docRoot}design/media/touch_feedback.webm" type="video/webm">
+    <source src="{@docRoot}design/media/touch_feedback.ogv" type="video/ogg">
+  </video>
+  <div class="figure-caption">
+    <div style="color:#a3a3a3;margin-left:130px;"><em>Click image to replay...</em></div>
   </div>
 </div>
 
@@ -96,4 +83,4 @@
   widgets, like lists and grid lists, have support for boundary feedback built
   in. If you’re building custom widgets, keep boundary feedback in mind and
   provide it from within your app.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
index 3c201f7..ec6fba2 100644
--- a/docs/html/design/style/typography.jd
+++ b/docs/html/design/style/typography.jd
@@ -1,5 +1,5 @@
 page.title=Typography
-page.tags="textview","font"
+page.tags=textview,font
 @jd:body
 
 <div class="layout-content-row">
diff --git a/docs/html/design/style/writing.jd b/docs/html/design/style/writing.jd
index cda17eb..4f62253 100644
--- a/docs/html/design/style/writing.jd
+++ b/docs/html/design/style/writing.jd
@@ -1,5 +1,5 @@
 page.title=Writing Style
-page.tags="dialog","toast","notification"
+page.tags=dialog,toast,notification
 @jd:body
 
 <h2 id="voa">Android's Voice</h2>
@@ -319,4 +319,4 @@
         ellipsis. </li>
     </ul>
   </li>
-</ul>
\ No newline at end of file
+</ul>
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
index ecdf2a8..1fabcb3 100644
--- a/docs/html/distribute/distribute_toc.cs
+++ b/docs/html/distribute/distribute_toc.cs
@@ -81,6 +81,7 @@
     <ul>
        <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">Tablet Stories</a></li>
        <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/games.html">Game Stories</a></li>
+       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/localization.html">Localization Stories</a></li>
     </ul>
   </li> 
 
@@ -90,6 +91,7 @@
       <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/about.html">About</a></li>
       <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/start.html">Get Started</a></li>
       <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/guidelines.html">Guidelines</a></li>
+      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/faq.html">FAQ</a></li>
       <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/contact.html">Sign Up</a></li>
     </ul>  
   </li>
diff --git a/docs/html/distribute/googleplay/edu/about.jd b/docs/html/distribute/googleplay/edu/about.jd
index cc131c64..20a0d4d 100644
--- a/docs/html/distribute/googleplay/edu/about.jd
+++ b/docs/html/distribute/googleplay/edu/about.jd
@@ -3,26 +3,25 @@
 excludeFromSuggestions=true
 @jd:body
 
-<div style="position:absolute;margin-left: 636px;
+    <div style="position:absolute;margin-left: 636px;
             margin-top:-76px;color:#777;">If you're interested<br>
             <a href="{@docRoot}distribute/googleplay/edu/contact.html"
             class="go-link"
             style="display: block;text-align: right;">SIGN UP</a></div>
 
     <div style="float:right;margin:0px 0px 24px 44px;">
-  <img src="{@docRoot}images/gp-edu-knum-landscape.png" style="width:420px" alt="" />
+  <img src="{@docRoot}images/gp-edu-apps-n7.jpg" style="width:420px" alt="" />
 </div>
 
 <p>Introducing Google Play for Education, the online destination where schools
 can find the right tablet content and tools for their students and teachers.</p>
 
-<p>With easy bulk ordering for groups, schools will be able to purchase and
-instantly distribute apps, videos, and books right to their students’
+<p>With easy bulk ordering for groups, schools can purchase and
+instantly distribute your apps, and videos right to their students’
 devices.</p>
 
-<p>The Google Play team looks forward to seeing you create first class content
-that will help schools. We want to help you create innovative educational apps,
-without having to knock on school doors to reach teachers and students.</p>
+<p>Google Play for Education can help your innovative educational apps
+gain visibility with the right audiences, without having to knock on school doors. </p>
 
 <p><a class="landing-page-link" style="text-align:right;" href="#video">Watch a Video</a></p>
 
@@ -32,36 +31,36 @@
 
 <h4>Get discovered</h4>
 
-<p>With Google Play for Education, teachers and administrators will be able to
+<p>With Google Play for Education, teachers and administrators can
 browse content by curriculum, grade, and standard &mdash; discovering the right
-content at the right time for their students. If your app offers an exciting new
-way to learn sixth grade algebra, we'll make it easy for math educators to find,
-purchase, and distribute your app to their classes.</p>
+content for their students. If your app offers an exciting new
+way to learn sixth grade algebra, math educators will be able to find,
+purchase, and distribute your app to their classes in a few clicks.</p>
 
 <h4>Reach more schools and students</h4>
 
-<p>Google has built a strong network of K-12 schools who are already using
-Google Apps for Education and other Google services. These schools are excited
-and looking forward to bringing your apps and content into their classrooms with
-Nexus tablets.</p>
+<p>Over 30 million students, faculty, and staff are already using
+Google Apps for Education and other Google services. Many of these schools are
+excited to take advantage of tablets with Google Play for Education and they
+look to bringing your apps into their classrooms,
+especially apps using Google sign-on.</p>
 
 <h4>Monetize effectively</h4>
-<p>With the wide launch of Google Play for Education later this year, educators
-will be able to make high-volume purchases using standard institutional payment
-mechanisms and distribute them to the students they want &mdash; whether it is a
-class of 30 or a district of 30,000.</p>
-
+<p>With Google Play for Education, educators are able to make high-volume purchases
+using standard institutional payment mechanisms and distribute them to the students
+they want &mdash; whether it is a class of 20 or a district of 20,000.</p>
+<code></code>
   </div>
 
   <div class="col-6 normal-links">
     <h3 style="clear:left">For Educators</h3>
     <h4>Android tablets in the classroom</h4>
     <p>Google Play for Education brings the innovation of Android technology
-into classrooms. Educators can set up and deploy large numbers of devices in
+into classrooms. School districts can set up and deploy large numbers of devices in
 just minutes or hours rather than days.</p>
 
     <h4>Curriculum-based discovery</h4>
-    <p>Powerful browsing tools let educators quickly discover apps, books,
+    <p>Powerful browsing tools let educators quickly discover apps,
 videos, and other content&mdash;with many recommended by teachers and
 categorized according to familiar Core Curriculum standards.  
 
diff --git a/docs/html/distribute/googleplay/edu/contact.jd b/docs/html/distribute/googleplay/edu/contact.jd
index 804d925..ca83438 100644
--- a/docs/html/distribute/googleplay/edu/contact.jd
+++ b/docs/html/distribute/googleplay/edu/contact.jd
@@ -5,11 +5,7 @@
 
 <p>We're looking forward to improving how students learn in the classroom as we
 bring your first-class educational content into schools across the United
-States, and to a broader international audience in the future. We'll soon share
-more information about Google Play for Education and our services that will help
-teachers and administrators buy, deploy, and use apps. </p>
-
-
+States, and to a broader international audience in the future. </p>
 
 <div class="vspace size-1">
   &nbsp;
@@ -35,8 +31,8 @@
     <p>
 If you're a school or system interested in tablets and Google Play for Education,
 complete the expression of interest form at <a href="http://www.google.com/edu/android">www.google.com/edu/android</a>.
-We'll be in touch later in the year as the program launches widely to schools.
   </p><a href="http://www.google.com/edu/android">School Interest Form »</a>
   </div>
 </div>
 
+
diff --git a/docs/html/distribute/googleplay/edu/faq.jd b/docs/html/distribute/googleplay/edu/faq.jd
new file mode 100644
index 0000000..6afc107
--- /dev/null
+++ b/docs/html/distribute/googleplay/edu/faq.jd
@@ -0,0 +1,372 @@
+page.title=Google Play for Education FAQ
+page.metaDescription=Questions and answers about Google Play for Education.
+excludeFromSuggestions=true
+@jd:body
+
+     <div style="position:absolute;margin-left: 636px;
+            margin-top:-76px;color:#777;">If you're interested<br>
+            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
+            class="go-link"
+            style="display: block;text-align: right;">SIGN UP</a></div>
+    
+ 
+    <style>
+  dt {
+    font-weight:bold;
+  }
+  </style>
+  
+<div id="qv-wrapper">
+<ol id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#business">Business Model</a></li>
+  <li><a href="#free_trials">Free Trials</a></li>
+  <li><a href="#discovery">Discovery</a></li>
+  <li><a href="#reviews">App Review Process</a></li>
+  <li><a href="#features">App Features</a></li>
+  <li><a href="#marketing">Marketing and ROI</a></li>
+  <li><a href="#devices">Devices</a></li>
+  <li><a href="#accounts">Accounts</a></li>
+</ol>
+</div>
+
+<p>
+  The sections below provide more information about Google Play for Education
+  and answer common questions that you might have about it.
+</p>
+
+
+<h2 id="business">Business Model and Monetization</h2>
+
+<dl>
+  <dt>
+    What is Google Play for Education?
+  </dt>
+
+  <dd>
+    Google Play for Education is a new online destination designed for schools.
+    Teachers can discover educational apps, books, and videos to meet the needs
+    of a single student, a classroom, or a whole district. Educators can browse
+    apps by grade, subject, keyword, or standard including common core.
+    Purchasing is done via PO with no credit card required. Apps are
+    distributed to tablets instantly via the cloud.
+  </dd>
+
+  <dt>
+    Is Google Play for Education primarily for students or educators?
+  </dt>
+
+  <dd>
+    The store on Google Play for Education is for educators, but its content is
+    for both educators and students. Teachers and administrators have the
+    ability to make purchases and control who within their school has access to
+    the purchase flows.
+  </dd>
+
+  <dt>
+    Will Google Play for Education support subscription purchases?
+  </dt>
+
+  <dd>
+    Currently, Google Play for Education supports one-time purchases. We are
+    investigating additional purchase mechanisms to enable more flexible
+    pricing models for developers and schools.
+  </dd>
+
+  <dt>
+    Why is it recommended to disable in-app purchases?
+  </dt>
+
+  <dd>
+    In-app purchase is currently not supported with Google Play for Education,
+    and a student device will block the Play transaction if a student attempts
+    to make an in-app purchase. To avoid student confusion in the classroom,
+    also recommend not including any in-app purchase buttons and other UI in
+    your application. We are investigating additional purchase mechanisms to
+    enable more flexible pricing models for developers and schools.
+  </dd>
+
+  <dt>
+    Is Google Play for Education restricted so only its users can purchase from
+    the Google Play for Education? Or will anyone be able to purchase from it?
+  </dt>
+
+  <dd>
+    Currently, only schools that are signed up for Google Play for Education
+    can make purchases on it.
+  </dd>
+
+  <dt>
+    Is there a way to differentiate an app's pricing between Google Play for
+    Education and Google Play?
+  </dt>
+
+  <dd>
+    For each app that you publish, you can set a single price that applies to
+    both Google Play and Google Play for Education &mdash. You can’t set a
+    different price for a given app (based on a single package name) in Google
+    Play for Education.
+  </dd>
+</dl>
+
+
+<h2 id="free_trials">Free Trials</h2>
+
+<dl>
+  <dt>
+    Can I offer free trials through Google Play for Education?
+  </dt>
+
+  <dd>
+    Google Play for Education doesn't currently support free trials. If you
+    want, you can offer a free version of your app with limited functionality
+    in Google Play for Education, but that app would need to be separate from
+    your paid app and be reviewed separately for educational content.
+  </dd>
+
+  <dt>
+    Can I offer a free trial through Google Play's "In-app Subscriptions with
+    Free Trials" feature?
+  </dt>
+
+  <dd>
+    Google Play for Education does not currently support In-app Billing or
+    In-app Subscriptions with free trials.
+  </dd>
+</dl>
+
+
+<h2 id="discovery">Discovery</h2>
+
+<dl>
+  <dt>
+    What are the categories in Google Play for Education?
+  </dt>
+
+  <dd>
+    Google Play for Education includes categories for all grade levels from
+    Kindergarten to 12 and the following subjects: English Language Arts, World
+    Languages, Mathematics, Science, Social Science, Elective, OER (Open
+    Education Resources), and Tools.
+  </dd>
+
+  <dt>
+    I created an app specifically for Google Play for Education and do not want
+    it to show up in Google Play. Is this possible?
+  </dt>
+
+  <dd>
+    Currently, it is not possible to publish an app Google Play for Education
+    and make it unavailable on Google Play.
+  </dd>
+
+  <dt>
+    If my app offers content for every level of education, how will it fit the
+    common-core standard filters?
+  </dt>
+
+  <dd>
+    If your app applies to multiple levels of education, then the app will show
+    up filtered results for in multiple levels.
+  </dd>
+</dl>
+
+
+<h2 id="reviews">App Review Process</h2>
+
+<dl>
+  <dt>
+    How are apps being reviewed? By whom and with what criteria?
+  </dt>
+
+  <dd>
+    Apps are being reviewed by a third party network of educators. These
+    educators assign the appropriate subject, grade, and common core standards
+    metadata, as well as evaluating whether the app meets the Google Play for
+    Education <a href=
+    "{@docRoot}distribute/googleplay/edu/guidelines.html">criteria for
+    classroom use</a>. You can learn more about the submission process and
+    criteria at <a href=
+    "http://developer.android.com/edu">developer.android.com/edu</a>.
+  </dd>
+
+  <dt>
+    How do I update my apps in Google Play for Education?
+  </dt>
+
+  <dd>
+    Developers can update their apps on Google Play for Education in the same
+    manner that they do for Google Play. App updates will not be reviewed prior
+    to being made available through Play for Education. However, we will
+    periodically review updated apps for quality.
+  </dd>
+
+  <dt>
+    Does the app maturity rating reflect solely what a user can do within my
+    Android app, or does the web version of my app influence the rating as
+    well?
+  </dt>
+
+  <dd>
+    The maturity rating that you set for your Android app refers only to the
+    content displayed in that application.
+  </dd>
+</dl>
+
+
+<h2 id="features">App Features</h2>
+
+<dl>
+  <dt>
+    Do I need separate builds of my phone and tablet apps for Google Play for
+    Education, or is it the exact same app that lives on Google Play?
+  </dt>
+
+  <dd>
+    We recommend you create one app and use it in both Google Play and Google
+    Play for Education.
+  </dd>
+
+  <dt>
+    What is the best way to get students’ work within apps sent back to their
+    teachers?
+  </dt>
+
+  <dd>
+    Many teachers have mentioned that the way apps treat this now is via an
+    email from a third party, which is not optimal for schools. As many schools
+    use Google Apps for Education, consider integrating your app with Google
+    Drive using the SDK which can be found here: <a class="external-link" href=
+    "https://developers.google.com/drive/about-sdk">developers.google.com/drive/about-sdk</a>.
+  </dd>
+
+  <dt>
+    How can developers test the teacher experience in Google Play for
+    Education? Is there a way to get an account to test it?
+  </dt>
+
+  <dd>
+    Currently, we are unable to provide developers with a test account to test
+    the Google Play for Education user experience. We are investigating ways to
+    allow developers to simulate the environment.
+  </dd>
+
+  <dt>
+    If I already have an app in the Chrome Apps Pack will I get some help
+    migrating this to Android?
+  </dt>
+
+  <dd>
+    If you’d like to reach users of Nexus tablets for schools we encourage you
+    to build a native app for the optimal user experience. Considerations for
+    building your app and instructions for registering it can be found at
+    <a href="http://developer.android.com/edu">developer.android.com/edu</a>.
+  </dd>
+</dl>
+
+
+<h2 id="marketing">Marketing and ROI</h2>
+
+<dl>
+  <dt>
+    What are you doing to promote these apps to educators?
+  </dt>
+
+  <dd>
+    Google Play for Education is an extension of Google Play targeting schools
+    and making discovery easier for educational apps. It helps your apps gain
+    visibility with the right audiences, without having to knock on school
+    doors. We are constantly referring to the highest quality apps in our
+    educator outreach. We have also developed a series of collections to help
+    educators quickly browse apps for the most common use cases.
+  </dd>
+
+  <dt>
+    How many installs have similar apps had on Play? How much can I expect to
+    make if I do an ROI analysis?
+  </dt>
+
+  <dd>
+    While we cannot disclose specific numbers, Google Play app listings provide
+    app download ranges for all apps.
+  </dd>
+
+  <dt>
+    What is the seasonality like for the education market? What are the key
+    timing considerations for app developers?
+  </dt>
+
+  <dd>
+    In the United States, school districts’ budget decisions go through a
+    planning phase in the Spring with budgets being released on July 1. We have
+    observed high purchase-volumes in the second quarter of the calendar year,
+    using up end-of-year budgets. New budget purchases begin in the third
+    quarter of the calendar year.
+  </dd>
+
+  <dt>
+    Is there a way to offer a special deal, such as a discount, only on Google
+    Play for Education and not on Google Play?
+  </dt>
+
+  <dd>
+    No, this is not possible. Pricing, including special offers, must be the
+    same between Google Play for Education and Google Play.
+  </dd>
+</dl>
+
+
+<h2 id="devices">Devices</h2>
+
+<dl>
+  <dt>
+    Which devices are available in the program? Will more be available?
+  </dt>
+
+  <dd>
+    Nexus 7 is available for shipment now, and the Asus Transformer will be
+    available in early 2014. We look forward to welcoming more Android devices
+    into the Google in Education family soon.
+  </dd>
+
+  <dt>
+    Can the devices be shared among many students?
+  </dt>
+
+  <dd>
+    No. Currently, this program is for one-to-one usage. Each student can login
+    to one specific tablet that is allocated to them.
+  </dd>
+</dl>
+
+
+<h2 id="accounts">
+  Accounts
+</h2>
+
+<dl>
+  <dt>
+    Will an app know whether a user is a teacher or student?
+  </dt>
+
+  <dd>
+    No, the app has no mechanism for knowing if it is running on a teacher’s
+    device or a student’s device. We recommend developers use their own user
+    database to enable this feature, where logins can be based on Google
+    Account information.
+  </dd>
+
+  <dt>
+    What log-in method do you recommend for an app on Google Play for
+    Education?
+  </dt>
+
+  <dd>
+    One of the key pieces of feedback we have heard multiple times from various
+    schools is that they prefer apps that offer Google Single Sign-on, so that
+    teachers and students do not need to remember multiple log-in credentials.
+    As schools in the program use Google Accounts and Google Apps for
+    Education, offering Google Single Sign-on is ideal.
+  </dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/guidelines.jd b/docs/html/distribute/googleplay/edu/guidelines.jd
index c1d3065..c4b719b 100644
--- a/docs/html/distribute/googleplay/edu/guidelines.jd
+++ b/docs/html/distribute/googleplay/edu/guidelines.jd
@@ -3,18 +3,16 @@
 excludeFromSuggestions=true
 @jd:body
 
-<div style="position:absolute;margin-left: 636px;
+   <div style="position:absolute;margin-left: 636px;
             margin-top:-76px;color:#777;">If you're interested<br>
             <a href="{@docRoot}distribute/googleplay/edu/contact.html"
             class="go-link"
             style="display: block;text-align: right;">SIGN UP</a></div>
 
-<div
-style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your apps in the Google Play for Education <a
-href="{@docRoot}distribute/googleplay/edu/start.html#program">pilot program</a>,
-getting it into the hands of participating schools and key influencers in the
-education technology community. See <a href="start.html">Get Started</a> to
+<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
+can now include your educational apps in the recently launched Google Play for Education program,
+getting it into the hands of participating schools and key influencers in the education technology
+community. See <a href="start.html">Get Started</a> to
 learn how to participate. </div>
 
 <p>The sections below list the guidelines and requirements for apps
@@ -28,8 +26,8 @@
 intuitive user experience on Android tablets.</p>
 
 <p>In addition, ensure that your app complies with the terms of a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.
-html" target="_policies">Google Play for Education Addendum</a>, as well as
+href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
+target="_policies">Google Play for Education Addendum</a>, as well as
 the standard  <a
 href="http://play.google.com/about/developer-content-policy.html"
 target="_policies">Google Play Developer Program Policies</a> and <a
@@ -229,14 +227,9 @@
 <ul>
 <li><em>Android version</em> &mdash; Test the app on devices running Android
 4.2. Google Play for Education devices will be running Android 4.2 or higher
-(API level 17).</li>
+(API level 17+).</li>
 <li><em>Proxy server</em> &mdash; Test the app in network environment that uses
 proxies. Many schools use proxies.</li>
-<li><em>Secondary user account</em> &mdash; Test the app using a secondary user
-account. Most Google Play for Education users will not be using the primary <a
-href="{@docRoot}about/versions/jelly-bean.html#42-multiuser">multiuser</a>
-account on their devices. For testing, create a secondary multiuser account on
-your tablet.</li>
 <li><em>No location services</em> &mdash; Test the app to make sure it works
 properly with location services disabled. Many schools will disable location
 services for student devices.</li>
@@ -249,4 +242,3 @@
 <li><em>No access to network</em> &mdash; Test the app to make sure it works
 properly when the device cannot connect to the internet. </li>
 </ul>
-
diff --git a/docs/html/distribute/googleplay/edu/index.jd b/docs/html/distribute/googleplay/edu/index.jd
index de5fe35..a27f82f 100644
--- a/docs/html/distribute/googleplay/edu/index.jd
+++ b/docs/html/distribute/googleplay/edu/index.jd
@@ -1,5 +1,5 @@
 page.title=Google Play for Education
-page.tags="Google Play","education","schools", "distribution"
+page.tags=Google Play,education,schools,distribution
 header.hide=1
 
 @jd:body
@@ -10,20 +10,21 @@
             style="display: block;text-align: right;">SIGN UP</a></div>
 
    <div class="marquee">
-  <div class="mainimg" style="position:absolute;margin-left:6px;margin-top:96px;">
-    <img src="{@docRoot}images/gp-edu-hero7.png" style="width:590px;">
+  <div class="mainimg" style="position:absolute;margin-left:34px;margin-top:57px;">
+    <img src="{@docRoot}images/gp-edu-hero14.jpg" style="width:670px;" />
   </div>
-  <div class="copy" style="position:relative;left:314px;margin-top:42px;width:420px;">
+  <div class="copy" style="position:relative;left:334px;margin-top:28px;width:420px;">
     <h1 style="margin-bottom:10px;">Google Play for Education</h1>
-    <p>A destination where schools can find great&nbsp;educational content in Google Play. 
-    Bulk&nbsp;purchase and instant distribution let&nbsp;educators bring your apps directly
-    to&nbsp;classrooms and schools.</p>
-    <p><a class="button" href="{@docRoot}distribute/googleplay/edu/about.html"
-      >Read More</a></p>
+    <p>Google Play for Education is a destination where schools can find great,
+    teacher-approved, educational apps and videos on Play Store. Teachers can filter
+    content by subject matter, grade and other criteria. Bulk purchase and instant
+    distribution let educators bring your apps directly to classrooms and schools.</p>
+    <p>If you have an educational app, join Google Play for Education.</p>
+    <p><a class="button" href="{@docRoot}distribute/googleplay/edu/about.html">Learn More</a></p>
   </div>
 </div>
 
-<div class="distribute-features col-13" style="clear:both;margin-top:253px;">
+<div class="distribute-features col-13" style="clear:both;margin-top:248px;">
   <div class="distribute-link">
   <ul>
     <li><a href="{@docRoot}distribute/googleplay/edu/about.html"><h5>About the Initiative</h5>
@@ -31,14 +32,16 @@
     <li><a href="{@docRoot}distribute/googleplay/edu/start.html"><h5>Get your Apps Ready</h5> 
     Follow these guidelines to make sure your app meets requirements and offers a great user experience. </a>
     </li>
-    <li class="last"><a href="{@docRoot}distribute/googleplay/edu/contact.html"><h5>Sign Up</h5>
-    Sign up here to be notified of the latest information regarding this program.</a>
+    <li class="last"><a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in"><h5>Submit your App</h5>
+    Use the Google Play Developer Console to mark your app for inclusion in the program and review by third-party
+    educators. </a>
     </li>
   </ul>
   </div>
 
 </div>
 
+
     
 
 
diff --git a/docs/html/distribute/googleplay/edu/start.jd b/docs/html/distribute/googleplay/edu/start.jd
index 78b8739..01d4406 100644
--- a/docs/html/distribute/googleplay/edu/start.jd
+++ b/docs/html/distribute/googleplay/edu/start.jd
@@ -3,18 +3,19 @@
 excludeFromSuggestions=true
 @jd:body
 
-<div style="position:absolute;margin-left: 636px;
+    <div class="jd-descr" itemprop="articleBody">
+    <div style="position:absolute;margin-left: 636px;
             margin-top:-76px;color:#777;">If you're interested<br>
             <a href="{@docRoot}distribute/googleplay/edu/contact.html"
             class="go-link"
             style="display: block;text-align: right;">SIGN UP</a></div>
 
 <div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your apps in the Google Play for Education <a href="#program">pilot program</a>,
-getting it into the hands of participating schools and key influencers in the education technology
-community. See the sections below to learn more.</div>
+can now include your educational apps in the Google Play for Education program,
+getting it into the hands of participating schools and key influencers in the
+education technology community. See the sections below to learn more.</div>
 
-<p>If you've got a great app for education or just an idea for one, plan to be a
+<p>If you've got a great app for education, be
 part of Google Play for Education to reach even more teachers and students. It's
 easy to participate, and you'll be able to offer new or existing Android apps
 using familiar tools and processes in Google Play.</p>
@@ -26,8 +27,8 @@
 your apps should meet. When your app is ready, you can opt-in to Google Play for
 Education from the Developer Console.</p>
 
-<p>Note that the initial launch of Google Play for Education is planned for Fall
-2013 and will include schools in the United States only, with support for other
+<p>Note that Google Play for Education is currently available to schools in the
+United States only, with support for schools in other
 countries to follow. At this time, please include your app in Google Play for
 Education only if it is targeting the <strong>US K-12 market</strong>. </p>
 
@@ -35,11 +36,12 @@
 <h2 id="participate">How to Participate</h2>
 
 <div style="float:right; padding-top:2em;"><img
-src="{@docRoot}images/gp-edu-process.png"></div>
+src="{@docRoot}images/gp-edu-process.png" /></div>
 
-<p>Google Play for Education lets you put your educational apps in front of a
+<p>Google Play for Education is a great way to put your educational apps in front of a
 new audience of teachers and students. You can develop and publish using
-familiar tools and processes, such as your existing Developer Console account
+familiar tools and processes, such as your existing <a
+href="https://play.google.com/apps/publish/">Developer Console</a> account
 and your current distribution and pricing settings. It's easy to participate
 &mdash; the sections below outline the process.</p>
 
@@ -109,7 +111,7 @@
 </div>
 </div>
 
-<p>When you've built your release-ready APK and tested to ensure that it meets
+<p>Once you've built your release-ready APK and tested to ensure that it meets
 the <a href="{@docRoot}distribute/googleplay/edu/guidelines.html">app guidelines</a>,
 upload it to the Developer Console, create your store listing, and set
 distribution options. If you aren't familiar with how to prepare for launch on
@@ -117,7 +119,8 @@
 href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist</a>. </p>
 
 <p>When your app is ready to publish, you can <em>opt-in</em> to Google Play for
-Education from the Developer Console. Opt-in means that you want your app to be
+Education directly from the <a
+href="https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means that you want your app to be
 made available to educators through Google Play for Education, including review,
 classification, and approval by our third-party educator network. Note that
 opt-in does not affect the availability of your app in Google Play Store.</p>
@@ -141,18 +144,21 @@
 opt-in. </li>
   <li>Under Pricing and Distribution, scroll down to find "Google Play for
 Education" and the opt-in checkbox. </li>
-  <li>Click the checkbox next to "Include my app in Google Play for
-Education..."</li>
-  <li>After you've opted-in, find the "Ads" and "In-app purchases" checkboxes below.
-Check each checkbox that applies. Your app's use of ads or in-app purchases will
+  <li>Click the checkbox next to "Include this application in Google Play for
+Education."</li>
+  <li>In the first dialog that appears, review the content policies and guidelines
+  and click "Continue" if your app meets the the policies and guidelines.</li>
+  <li>In next dialog that appears, shown below, find the "Ads" and "In-app purchases" radio
+  buttons. Check each option that applies. Your app's use of ads or in-app purchases will
 be shown to educators when they are browsing your app. </li>
   <li>Click "Save" to save your Pricing and Distribution changes.</li>
 </ol>
 
 <div style="clear:both;margin-top:1.5em;margin-bottom:1.5em;width:660px;">
-<img src="{@docRoot}images/gp-edu-optin.png" style="border:2px solid #ddd;width:660px;">
-<p class="image-caption"><span style="font-weight:500;">Opt-in for apps</span>:
-Include your app in Google Play for Education by opting-in from the Developer Console.</p>
+<img src="{@docRoot}images/gp-edu-ads-iab.png" style="border:2px solid #ddd;width:660px;" />
+<p class="image-caption"><span style="font-weight:500;">Ads and in-app purchase</span>:
+When you opt-in to Google Play for Education, make sure to declare your app's use of ads and
+in-app purchases.</p>
 </div>
 
 <p>Once you save changes and publish your app, the app will be submitted to our
@@ -176,23 +182,20 @@
 
 <p>Our third-party educator network will evaluate apps according to educational
 value and alignment with K-12 core standards, then assign the metadata for
-subject, grade level, and core curriculum that makes them easily browseable for
+subject, grade level, and core curriculum that makes them easily browsable for
 educators. To understand how your apps will be evaluated, please see the <a
 href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
 Apps</a> document.</p>
 
 <p>As soon as you opt-in to Google Play for Education and publish, your app is
 queued for review by our third-party educator network. The review and approval
-process can take <strong>3-4 weeks or more</strong>. You'll receive notification
+process can take four weeks or more</strong>. You'll receive notification
 by email (to your developer account address) when the review is complete, with a
 summary of the review results. </p>
 
-<p class="note"><strong>Note</strong>: Until the full product launch in Fall
-2013, please expect the initial review of your app to take longer than usual.
-</p>
-
 <p>At any time, you can check the review and approval status of your app in the
-Developer Console, under "Google Play for Education" in the app's Pricing and
+<a href="https://play.google.com/apps/publish/">Developer Console</a>, under
+"Google Play for Education" in the app's Pricing and
 Distribution page. There are three approval states:</p>
 
 <ul>
@@ -200,9 +203,6 @@
 is not yet complete.</li>
 <li><em>Approved</em> &mdash; Your app was reviewed and approved. The app
 will be made available directly to educators through Google Play for Education.
-Until the full product launch later this year, your app will be available to a
-limited number of educators through the <a
-href="{@docRoot}distribute/googleplay/edu/start.html#program">pilot program</a>.
 Once your app is approved, you can update it at your convenience without needing
 another full review. </li>
 <li><em>Not approved</em> &mdash; Your app was reviewed and not approved.
@@ -215,50 +215,14 @@
 
 <h3 id="appeal">5. Get support or appeal your review results</h3>
 
-<p>After your app is reviewed you'll receive an email giving you the review
-results, including whether the app was approved, how the app was classified, and
+<p>After your app is reviewed you'll receive an email giving you the
+results, including information on whether the app was approved and
 what issues may need to be addressed. You'll receive the email at the address
 you specified for your developer account. </p>
 
-<p>If you believe your app was reviewed or classified incorrectly, you will be
-able to appeal and request reconsideration. Watch for more information on the
-appeal process and links in the weeks to come.</p>
+<p>If your app has issues that need to be addressed, make the necessary
+adjustments, upload your app, and then resubmit the app to Google Play for
+Education through the Developer Console using process described above. Your app
+will be queued for review and you'll receive the review results by email just
+as before.</p>
 
-<p class="note"><strong>Note</strong>: Support and appeal forms are not yet
-available, but will be available soon.</p>
-
-
-<h2 id="program">Including Your Apps in the Pilot Program</h2>
-
-<p>Leading up to the Fall 2013 launch, the Google Play for Education team is
-conducting an extensive series of pilots that include schools and students across
-the United States. Educators in participating schools can browse for apps and
-purchase them in bulk, then deploy them instantly to teacher and student
-devices. </p>
-
-<h3 id="pilot">Early opt-in and publishing</h3>
-<p>As an app developer, you can take part in the pilot program, getting your app
-into the hands of schools and key influencers in the education technology
-community. It's a great way to get early feedback on your educational app. </p>
-
-<p>To offer your app in the pilot program, prepare the app and ensure that it meets
-the <a href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines
-for Apps</a>. Then opt-in to Google Play for Education and publish as soon
-as you are ready. Once your app is approved during review by our third-party
-educator network, it will be made available to educators in the pilot program
-right away. Note that during the pilot program, the review and approval process
-may take longer than usual.</p>
-
-<h3 id="launch">Full launch to US schools</h3>
-<p>The initial launch of Google Play for Education is planned for Fall 2013. The
-pilot program and full launch will include schools in the United States only,
-with support for schools in other countries to follow. </p>
-
-<p>At this time, you should include your app in Google Play for Education only
-if it is targeting the US K-12 market. </p>
-
-<h3 id="more">More information</h3>
-
-<p>If you'd like to be notified by email of the latest information about Google Play
-for Education, visit the <a href="{@docRoot}distribute/googleplay/edu/contact.html">
-Sign Up</a> page and fill out the form. </p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/publish/localizing.jd b/docs/html/distribute/googleplay/publish/localizing.jd
index 29b27c8..30f10b7 100644
--- a/docs/html/distribute/googleplay/publish/localizing.jd
+++ b/docs/html/distribute/googleplay/publish/localizing.jd
@@ -1,5 +1,5 @@
 page.title=Localization Checklist
-page.tags="localize","localization","resources", "formats", "l10n"
+page.tags=localize,localization,resources,formats,l10n
 @jd:body
 
 <div id="qv-wrapper"><div id="qv">
@@ -293,7 +293,7 @@
 <tr>
 <td><p>Related resources:</p>
 <ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}topics/resources/string-resource.html">String Resources</a></strong> &mdash; Developer guide explaining how to use string resources in your UI.</li>
+<li><strong><a href="{@docRoot}guide/topics/resources/string-resource.html">String Resources</a></strong> &mdash; Developer guide explaining how to use string resources in your UI.</li>
 <li><strong><a href="{@docRoot}design/style/writing.html">Writing Style</a></strong> &mdash; Android Design guidelines for voice and style in your UI.</li>
 <li><strong><a class="external-link" href="http://en.wikipedia.org/wiki/XLIFF">XML Localisation Interchange File Format (XLIFF)</a></strong> &mdash; Background information on XLIFF.</li>
 </ul>
@@ -372,24 +372,24 @@
 <p>After the translations are merged back into your app, start <a
 href="#testing">testing the localized app</a>.</p>
 
+<h4 id="gp-trans">Purchase professional translations through Google Play
+<br />App Translation Service</h4>
+
 <div class="sidebox-wrapper">
 <div class="sidebox">
-<h2>Join the translation pilot</h2>
-<p>Google Play is offering translation services as part of a pilot
-program. If you're interested, sign up on the APK page in your
-Developer Console.</p>
+<h2>App Translations in Google Play</h2>
 
-<p>If you join, also try the <a
+<p>Hear from developers who have used the Google Play App Translation Service in <a
+href="{@docRoot}distribute/googleplay/spotlight/localization.html">Developer
+Stories: Localization in Google Play</a>.</p>
+
+<p>To make it easy to export your app's strings and import
+the finished translations into your project, try the <a
 href="{@docRoot}sdk/installing/installing-adt.html#tmgr">
-ADT Translation Manager Plugin</a>, which makes it easy to upload
-your strings to the Developer Console and download translations
-right into your project. </div>
+ADT Translation Manager Plugin</a>.</div>
 </div>
 
-<h4 id="gp-trans">Purchase professional translations through the
-Developer Console</h4>
-
-<p>Google Play can help you quickly find and purchase translations of your app.
+<p>Google Play App Translation Service can help you quickly find and purchase translations of your app.
 In the Developer Console, you can browse a list of third-party vendors who are
 pre-qualified by Google to offer high-quality translation at competitive prices.
 You can upload the strings you want translated, select the languages you want to
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 5593f4f..6af3eea 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -1,5 +1,5 @@
 page.title=Launch Checklist
-page.tags="publishing","launch","Google Play", "Developer Console"
+page.tags=publishing,launch,Google Play,Developer Console
 @jd:body
 
 <div id="qv-wrapper"><div id="qv">
@@ -671,7 +671,7 @@
 <li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113477&topic=2364761&ctx=topic">Supporting your users
 </a></strong> &mdash; Help Center document describing options for supporting users.</li>
 <li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1153479">In-app Billing</a></strong> &mdash; Help Center document describing how to correctly set up In-app Billing.</li>
-<li><strong><a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138001">Issuing Refunds</a></strong> &mdash;  -- Help Center document describing how to issue refunds.</li>
+<li><strong><a href="https://support.google.com/payments/answer/2741495?rd=1">Issuing Refunds</a></strong> &mdash;  -- Help Center document describing how to issue refunds.</li>
 </ul>
 </td>
 </tr>
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
index c599628..b501f20 100644
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -55,7 +55,7 @@
           <div style="width:700px;">
           <p style="margin-top:26px;
                     margin-bottom:12px;">
-          Bangalore-based developers <a href="//play-next-dogfood.corp.google.com/store/apps/details?id=in.redbus.android">redBus.in</a> are bringing the sophistication and convenience of air-travel booking to bus transit. Hear how Android is helping them deliver a superior travel experience to millions of daily bus riders in India.</p>
+          Bangalore-based developers <a href="//play.google.com/store/apps/details?id=in.redbus.android">redBus.in</a> are bringing the sophistication and convenience of air-travel booking to bus transit. Hear how Android is helping them deliver a superior travel experience to millions of daily bus riders in India.</p>
            </div>
            <iframe style="float:left;
              margin-right:24px;
diff --git a/docs/html/distribute/googleplay/spotlight/localization.jd b/docs/html/distribute/googleplay/spotlight/localization.jd
new file mode 100644
index 0000000..ae5993d
--- /dev/null
+++ b/docs/html/distribute/googleplay/spotlight/localization.jd
@@ -0,0 +1,328 @@
+page.title=Developer Stories: Localization in Google Play
+walkthru=0
+header.hide=0
+
+@jd:body
+
+<p>
+  As you build your app and distribute it across the world through Google Play,
+  localization becomes an increasingly important tool to reach more users.
+  Localization involves a <a href=
+  "{@docRoot}distribute/googleplay/publish/localizing.html">variety of tasks</a>, but
+  most important is creating quality translations of your app's UI strings and
+  marketing materials.
+</p>
+
+<p>
+  Managing the translation process across multiple languages can be a
+  challenge, especially if you need to locate translators on your own. That’s
+  why Google Play offers the App Translation Service right from the Developer
+  Console. It's a single place where you can go to source professional
+  translators, get cost estimates, and then send your strings and other
+  materials for translation.
+</p>
+
+<p>
+  Here are some stories from developers who have used Google Play's App Translation
+  Service to localize their apps and the results they've seen as they've
+  expand their offerings beyond a single language.
+</p>
+
+<!-- START STORY -->
+
+<div style="margin-bottom:2em;padding-top:10px;" id="zombieragdoll">
+
+<h3 style="line-height:1.25em">Zombie Ragdoll: Improved user engagement<br /> with localized versions</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh4.ggpht.com/m-Ew8c8C_nGctbP6PSPGOaVNnGFryReOE2yHXJ9Z6Prk1nsDyx5w5TmWfg-P5N3HypA=w124">
+
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5>
+
+    <ul>
+      <li><a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">Zombie Ragdoll</a></li>
+      <li>A fun zombie-based physics game</li>
+    </ul>
+
+    <h5>Localization Results</h5>
+
+    <ul>
+      <li>Increased engagement because of appeal of the localized version</li>
+      <li>80% of installs came from users of non-English languages</li>
+      </ul>
+
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
+        <img alt="Android app on Google Play"
+         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+
+<p>
+  The 2013 Google I/O talks about <a href=
+  "https://developers.google.com/events/io/sessions/326345917">Building Android
+  Apps for a Global Audience</a> and <a href=
+  "https://developers.google.com/events/io/sessions/326455375">What’s New for
+  Developers in Google Play</a> inspired developers at RV AppStudios to go global
+  from very beginning for their new game, Zombie Ragdoll. They launched Zombie
+  Ragdoll in August 2013, localized into 20 languages.
+</p>
+
+<p>
+  They quickly saw the impact of their decision to ship simultaneously in
+  multiple languages through increased non-English installs and improved
+  engagement with users worldwide. In addition, they started getting
+  significant usage in countries where their apps had not been as popular
+  before. They are seeing great traction in countries like Vietnam, Russia,
+  Philippines and Thailand.
+</p>
+
+<p>
+  Vivek Dave, founder of RV AppStudios, credits the success of Zombie Ragdoll
+  to localization:
+</p>
+
+<p>
+  "The value of localization is clear, it helps discoverability and helps
+  connect with the users in other countries. So when the localization
+  opportunity arose, we immediately jumped on it. Android is worldwide, and we
+  would be severely limiting ourselves if we focused on English as the only
+  language.
+</p>
+
+<p>
+  "The App Translation Service offered in the Google Play Developer Console is
+  extremely easy to use and the pricing is very attractive. Developers with
+  limited localization experience can easily create, upload, and translate
+  their app."
+</p>
+
+
+<p>
+  RV AppStudios not only localizes the text within the game, but also localizes
+  the game assets to a specific country/culture. Dave says, “Users want a
+  personalized experience, and by offering a localized game with translation of
+  text and graphic assets, we believe users will connect at a much deeper level
+  with the game.”
+</p>
+
+
+  <div style="margin-top:8px;float:left;margin-right:24px;">
+    <img src="{@docRoot}images/distribute/zombie-ragdoll-n5-land.jpg" style="width:470px;">
+  </div>
+
+
+    <div style="margin-top:128px;">
+      <p class="img-caption"><strong>Hindi version of Zombie Ragdoll</strong>:
+      Localized screenshots and videos in the app's Google Play listing go a
+      long way toward increasing the number of installs.</p>
+    </div>
+
+  </div>
+
+</div> <!-- END STORY -->
+
+<!-- START STORY -->
+
+<div style="margin-bottom:2em;padding-top:18px;clear:both;" id="sayhichat">
+
+<h3>SayHi Chat: Install growth and user engagement<br />
+  from professional translations</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh5.ggpht.com/qiL6CF1Hktz618T3mbGrxvm_OoeheQ78FgG7zr90C2MCRiz4IDQsbKuHT4xQGiWEU8o=w124">
+
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5>
+
+    <ul>
+      <li><a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">SayHi Chat,
+      Love, Meet, Dating</a></li>
+      <li>A social app to help you find people nearby</li>
+    </ul>
+
+    <h5>Localization Results</h5>
+
+    <ul>
+      <li>120% growth in language installs for new languages added</li>
+      <li>~20% increase in revenue and ~50% increase in User Reviews in the new
+        languages</li>
+      </ul>
+
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">
+        <img alt="Android app on Google Play"
+         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+
+<p>
+  The SayHi Chat app started out only in Japanese, Chinese and English. It soon
+  became one of the most popular apps in Japan, Hong Kong, and Taiwan. The
+  SayHi team realized it was time to launch in more languages, as the language
+  barrier was restricting how fast SayHi could grow globally. </p>
+
+  <p>Yan Shi, senior
+  developer at SayHi, says: "We checked Google Analytics for our DAU and user
+  growth numbers in each country, we also looked at total Android and iOS users
+  in those markets before finalizing our next set of languages.
+</p>
+
+  <div style="margin-top:8px;float:left;width:270px;">
+    <img src="{@docRoot}images/distribute/hichat-n5-port.jpg" style="width:240px;margin-right:48px;">
+  </div>
+
+<p>
+  SayHi used the App Translation Service to launch in 13 additional languages
+  in August 2013 and immediately saw 120% increase in install rates. In
+  addition, they are seeing their app ranked in Top 10 apps in countries like
+  Poland and Italy.
+</p>
+
+<p>Notably, they saw steady growth in Spain after replacing their previous
+  non-professional Spanish translation with a professional one produced through
+  the App Translation Service.</p>
+
+<p>
+  Yan Shi adds, “The App Translation Service is really easy to use and
+  the completion time for translation requests is very good.”
+</p>
+
+    <div style="width:600px;margin-top:98px;padding:0;">
+      <p class="img-caption"><strong>Arabic version of SayHi Chat</strong>:
+        User engagement increased significantly with
+        the localized version.</p>
+    </div>
+
+  </div>
+</div> <!-- END STORY -->
+
+
+<div style="margin-bottom:2em;clear:both;padding-top:18px;" id="g4a"><!-- START STORY -->
+
+<h3 style="line-spacing:1.25em;">G4A Indian Rummy: Benefitting from ease-of-use and<br /> fast turnaround time</h3>
+
+  <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
+            -moz-border-radius: 5px;
+            border-radius: 5px height:78px;
+            width: 78px;
+            float: left;
+            margin: 12px 20px 9px 20px;" src=
+            "https://lh4.ggpht.com/IxSyQgO0LWzPRoLfCrER06-0kr6aMAa2azF7eNYB30EBZAGOLYJUZulknPockbTlDYU=w124">
+
+  <div style="list-style: none;height:100%;
+  float: right;
+  border-top: 1px solid #9C0;
+  width: 220px;
+  margin: 4px 20px;padding: .5em;">
+
+    <h5>About the app</h5>
+
+    <ul>
+      <li><a href="https://play.google.com/store/apps/details?id=org.games4all.android.games.indianrummy.prod">G4A Indian Rummy</a></li>
+      <li>A card game in which the players try to form sets and sequences of cards</li>
+    </ul>
+
+    <h5>Localization Results</h5>
+
+    <ul>
+      <li>Double the number of users in French and German languages</li>
+      <li>300% increase in user engagement with localized version</li>
+      </ul>
+
+    <div style="padding:.5em 0 0 1em;">
+      <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
+        <img alt="Android app on Google Play"
+         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+      </a>
+    </div>
+  </div>
+
+  <div style="line-height:1.4em;">
+
+<p>
+  Games4All (G4A) is the developer of Indian Rummy and a variety of games that
+  they distribute broadly to users around the world. After noticing that
+  certain apps had become especially popular in specific countries, they
+  decided to localize those apps. Initially they used a local agency to do
+  the translation and got great results &mdash; the number of users in
+  that language increased tremendously when they released the localized
+  version.
+</p>
+
+<p>
+  Building on that success, G4A expanded their localization goals but
+  found that translation quality varied across their vendors and costs limited the
+  language/game combinations they could try. That's when G4A decided to try the
+  App Translation Service.
+</p>
+
+<p>
+  Founder Pieter Olivier says, "When we heard that the App Translation
+  Service was available in the Developer Console, we jumped at the opportunity.
+  We've now been using the App Translation Service for several months and found
+  that the cost per translation is much lower than with local companies and the
+  process is much easier."
+</p>
+
+<p>So far, G4A has translated the game Indian Rummy into five languages through
+   the App Translation Service.</p>
+
+<p>
+  Olivier continues, "The first thing we did was convert all of our texts into
+  the strings.xml format. After that using the service was extremely easy and
+  straightforward. In contrast, our previous experiences with translation
+  agencies were much more difficult: files often required extensive conversion
+  operations to make them usable, and turnaround times varied wildly.
+</p>
+
+<p>
+  "With the App Translation Service, the turnaround time is usually measured in
+  days instead of weeks that we were used to with traditional translation
+  agencies."
+</p>
+
+  <div style="margin-top:14px;float:left;margin-right:24px;">
+    <img src="{@docRoot}images/distribute/indian-rummy-n4-land.jpg" style="width:470px;">
+  </div>
+
+    <div style="margin-top:158px;">
+      <p class="img-caption"><strong>Dutch
+      version of Indian Rummy</strong>: Making slight changes to games rules based on
+      local nuances was key to success of the game.</p>
+    </div>
+
+  </div>
+
+
+
+</div> <!-- END STORY -->
\ No newline at end of file
diff --git a/docs/html/google/gcm/adv.jd b/docs/html/google/gcm/adv.jd
index 1360624..567b12c 100644
--- a/docs/html/google/gcm/adv.jd
+++ b/docs/html/google/gcm/adv.jd
@@ -22,7 +22,12 @@
   </ol>
 </li>
 <li><a href="#retry">Automatic Retry Using Exponential Back-Off</a></li>
-<li><a href="#unreg">How Unregistration Works</a></li>
+<li><a href="#unreg">Unregistration</a>
+  <ol>
+    <li><a href="#unreg-why">Why you should rarely unregister</a></li>
+    <li><a href="#unreg-how">How unregistration works</a></li>
+  </ol>
+</li>
 <li><a href="#collapsible">Send-to-Sync vs. Messages with Payload</a>
   <ol>
     <li><a href="#s2s">Send-to-sync messages</a></li>
@@ -31,7 +36,8 @@
     </ol>
 </li>
 <li><a href="#ttl">Setting an Expiration Date for a Message</a> </li>
-<li><a href="#throttling"></a><a href="#multi-senders">Receiving Messages from Multiple Senders</a></li>
+<li><a href="#throttling"></a><a href="#multi-senders">Receiving Messages from
+Multiple Senders</a></li>
 </ol>
 
 </div>
@@ -42,17 +48,56 @@
 
 
 <h2 id="msg-lifetime">Lifetime of a Message</h2>
-<p>When a 3rd-party server posts a message to GCM and receives a message ID back, it does not mean that the message was already delivered to the device. Rather, it means that it was accepted for delivery. What happens to the message after it is accepted depends on many factors.</p>
-<p>In the best-case scenario, if the device is connected to GCM, the screen is on, and there are no throttling restrictions (see <a href="#throttling">Throttling</a>), the message will be delivered right away.</p>
+<p>When a 3rd-party server posts a message to GCM and receives a message ID back,
+it does not mean that the message was already delivered to the device. Rather, it
+means that it was accepted for delivery. What happens to the message after it is
+accepted depends on many factors.</p>
+
+<p>In the best-case scenario, if the device is connected to GCM, the screen is on,
+and there are no throttling restrictions (see <a href="#throttling">Throttling</a>),
+the message will be delivered right away.</p>
+
 <p>If the device is connected but idle, the message will still be
-delivered right away unless the <code>delay_while_idle</code> flag is set to true. Otherwise, it will be stored in the GCM servers until the device is awake. And that's where the <code>collapse_key</code> flag plays a role: if there is already a message with the same collapse key (and registration ID) stored and waiting for delivery, the old message will be discarded and the new message will take its place (that is, the old message will be collapsed by the new one). However, if the collapse key is not set, both the new and old messages are stored for future delivery.</p>
+delivered right away unless the <code>delay_while_idle</code> flag is set to true.
+Otherwise, it will be stored in the GCM servers until the device is awake. And
+that's where the <code>collapse_key</code> flag plays a role: if there is already
+a message with the same collapse key (and registration ID) stored and waiting for
+delivery, the old message will be discarded and the new message will take its place
+(that is, the old message will be collapsed by the new one). However, if the collapse
+key is not set, both the new and old messages are stored for future delivery.
+Collapsible messages are also called <a href="#s2s">send-to-sync messages</a>.</p>
 
-<p class="note"><strong>Note:</strong> There is a limit on how many messages can be stored without collapsing. That limit is currently 100. If the limit is reached, all stored messages are discarded. Then when the device is back online, it receives a special message indicating that the limit was reached. The application can then handle the situation properly, typically by requesting a full sync.</p>
+<p class="note"><strong>Note:</strong> There is a limit on how many messages can
+be stored without collapsing. That limit is currently 100. If the limit is reached,
+all stored messages are discarded. Then when the device is back online, it receives
+a special message indicating that the limit was reached. The application can then
+handle the situation properly, typically by requesting a full sync.
+<br><br>
+Likewise, there is a limit on how many <code>collapse_key</code>s you can have for
+a particular device. GCM allows a maximum of 4 different collapse keys to be used
+by the GCM server per device
+any given time. In other words, the GCM server can simultaneously store 4 different
+send-to-sync messages, each with a different collapse key. If you exceed this number
+GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.
+See <a href="#s2s">Send-to-sync messages</a> for more information.
+</p>
 
-<p>If the device is not connected to GCM, the message will be stored until a connection is established (again respecting the collapse key rules). When a connection is established, GCM will deliver all pending messages to the device, regardless of the <code>delay_while_idle</code> flag. If the device never gets connected again (for instance, if it was factory reset), the message will eventually time out and be discarded from GCM storage. The default timeout is 4 weeks, unless the <code>time_to_live</code> flag is set.</p>
+<p>If the device is not connected to GCM, the message will be stored until a
+connection is established (again respecting the collapse key rules). When a connection
+is established, GCM will deliver all pending messages to the device, regardless of
+the <code>delay_while_idle</code> flag. If the device never gets connected again
+(for instance, if it was factory reset), the message will eventually time out and
+be discarded from GCM storage. The default timeout is 4 weeks, unless the
+<code>time_to_live</code> flag is set.</p>
 
-<p>Finally, when GCM attempts to deliver a message to the device and the application was uninstalled, GCM will discard that message right away and invalidate the registration ID. Future attempts to send a message to that device will get a <code>NotRegistered</code> error. See <a href="#unreg">How Unregistration Works</a> for more information.</p>
-<p>Although is not possible to track the status of each individual message, the Google APIs Console stats are broken down by messages sent to device, messages collapsed, and messages waiting for delivery.</p>
+<p>Finally, when GCM attempts to deliver a message to the device and the
+application was uninstalled, GCM will discard that message right away and
+invalidate the registration ID. Future attempts to send a message to that device
+will get a <code>NotRegistered</code> error. See <a href="#unreg">
+How Unregistration Works</a> for more information.</p>
+<p>Although is not possible to track the status of each individual message, the
+Google APIs Console stats are broken down by messages sent to device, messages
+collapsed, and messages waiting for delivery.</p>
 
 <h2 id="throttling">Throttling</h2>
 <p>To prevent abuse (such as sending a flood of messages to a device) and
@@ -74,107 +119,112 @@
 efficiency reasons.</p>
 
 <h2 id="reg-state">Keeping the Registration State in Sync</h2>
-<p>Whenever the application receives a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent with a <code>registration_id</code> extra, it should save the ID for future use, pass it to the 3rd-party server to complete the registration, and keep track of whether the server completed the registration. If the server fails to complete the registration, it should try again or unregister from GCM.</p>
+<p>Whenever the application registers as described in
+<a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a>,
+it should save the registration ID for future use, pass it to the
+3rd-party server to complete the registration, and keep track of
+whether the server completed the registration. If the server fails
+to complete the registration, it should try again or unregister from GCM.</p>
+
 <p>There are also two other scenarios that require special care:</p>
 <ul>
   <li>Application update</li>
   <li>Backup and restore
   </li>
 </ul>
-<p>When an application is updated, it should invalidate its existing registration ID, as it is not guaranteed to work with the new version.  Because there is no lifecycle method called when the application is updated, the best way to achieve this validation is by storing the current application version when a registration ID is stored. Then when the application is started, compare the stored value with the current application version. If they do not match, invalidate the stored data and start the registration process again.</p>
+<p>When an application is updated, it should invalidate its existing registration
+ID, as it is not guaranteed to work with the new version.  Because there is no
+lifecycle method called when the application is updated, the best way to achieve
+this validation is by storing the current application version when a registration
+ID is stored. Then when the application is started, compare the stored value with
+the current application version. If they do not match, invalidate the stored data
+and start the registration process again.</p>
 
-<p>Similarly, you should not save the registration ID when an application is backed up. This is because the registration ID could become invalid by the time the application is restored, which would put the application in an invalid state  (that is, the application thinks it is registered, but the server and GCM do not store that registration ID anymore&mdash;thus the application will not get more messages).</p>
+<p>Similarly, you should not save the registration ID when an application is
+backed up. This is because the registration ID could become invalid by the time
+the application is restored, which would put the application in an invalid state
+(that is, the application thinks it is registered, but the server and GCM do not
+store that registration ID anymore&mdash;thus the application will not get more
+messages).</p>
 <h3 id="canonical">Canonical IDs</h3>
-<p>On the server side, as long as the application is behaving well, everything should work normally. However, if a bug in the application triggers multiple registrations for the same device, it can be hard to reconcile state and you might end up with duplicate messages.</p>
-<p>GCM provides a facility called &quot;canonical registration IDs&quot; to easily recover from these situations. A canonical registration ID is defined to be the ID of the last registration requested by your application. This is the ID that the server should use when sending messages to the device.</p>
-<p>If later on you try to send a message using a different registration ID, GCM will process the request as usual, but it will include the canonical registration ID in the <code>registration_id</code> field of the response. Make sure to replace the registration ID stored in your server with this canonical ID, as eventually the ID you're using will stop working.</p>
+<p>On the server side, as long as the application is behaving well, everything
+should work normally. However, if a bug in the application triggers multiple
+registrations for the same device, it can be hard to reconcile state and you might
+end up with duplicate messages.</p>
+<p>GCM provides a facility called &quot;canonical registration IDs&quot; to easily
+recover from these situations. A canonical registration ID is defined to be the ID
+of the last registration requested by your application. This is the ID that the
+server should use when sending messages to the device.</p>
+<p>If later on you try to send a message using a different registration ID, GCM
+will process the request as usual, but it will include the canonical registration
+ID in the <code>registration_id</code> field of the response. Make sure to replace
+the registration ID stored in your server with this canonical ID, as eventually
+the ID you're using will stop working.</p>
 
 <h2 id="retry">Automatic Retry Using Exponential Back-Off</h2>
 
-<p>When the application receives a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent with the <code>error</code> extra set as <code>SERVICE_NOT_AVAILABLE</code>, it should retry the failed operation (register or unregister).</p>
-<p>In the simplest case, if your application just calls <code>register</code> and GCM is not a fundamental part of the application, the application could simply ignore the error and try to register again the next time it starts. Otherwise, it should retry the previous operation using exponential back-off. In exponential back-off, each time there is a failure, it should wait twice the previous amount of time before trying again. If the register (or unregister) operation was synchronous, it could be retried in a simple loop. However, since it is asynchronous, the best approach is to schedule a pending intent to retry the operation. The following steps describe how to implement this in the <code>MyIntentService</code> example used above:</p>
-<ol>
-  <li> Create a random token to verify the origin of the retry intent:
+<p>When registration or unregistration fails, the app should retry the failed operation.</p>
+<p>In the simplest case, if your application attempts to register and GCM is not a
+fundamental part of the application, the application could simply ignore the error
+and try to register again the next time it starts. Otherwise, it should retry the
+previous operation using exponential back-off. In exponential back-off, each time
+there is a failure, it should wait twice the previous amount of time before trying
+again. If the register (or unregister) operation was synchronous, it could be retried
+in a simple loop. However, since it is asynchronous, the best approach is to schedule
+a {@link android.app.PendingIntent} to retry the operation.
 
-<pre class="prettyprint pretty-java">private static final String TOKEN =
-        Long.toBinaryString(new Random().nextLong());
-</pre>
+<h2 id="unreg">Unregistration</h2>
 
-  <li> Change the <code>handleRegistration()</code> method so it creates the pending intent when appropriate:</li>
+<p>This section explains when you should unregister in GCM and what happens
+when you do.</p>
 
-<pre class="prettyprint pretty-java">...
-if (error != null) {
- if ("SERVICE_NOT_AVAILABLE".equals(error)) {
-   long backoffTimeMs = // get back-off time from shared preferences
-   long nextAttempt = SystemClock.elapsedRealtime() + backoffTimeMs;
-   Intent retryIntent = new Intent("com.example.gcm.intent.RETRY");
-   retryIntent.putExtra("token", TOKEN);
-   PendingIntent retryPendingIntent =
-       PendingIntent.getBroadcast(context, 0, retryIntent, 0);
-   AlarmManager am = (AlarmManager)   
-       context.getSystemService(Context.ALARM_SERVICE);
-   am.set(AlarmManager.ELAPSED_REALTIME, nextAttempt, retryPendingIntent);
-   backoffTimeMs *= 2; // Next retry should wait longer.
-   // update back-off time on shared preferences
- } else {
-   // Unrecoverable error, log it
-   Log.i(TAG, "Received error: " + error);
-}
-...</pre>
-<p> The back-off time is stored in a shared preference. This ensures that it is persistent across multiple activity launches. The name of the intent does not matter, as long as the same intent is used in the following steps.</p></li>
+<h3 id="unreg-why">Why you should rarely unregister</h3>
 
-  <li> Change the <code>onHandleIntent()</code> method adding an <code>else if</code> case for the retry intent:</li>
+<p>A registration ID (regID) represents a particular Android application running
+on a particular device. You should only need to unregister in rare cases, such as
+if you want an app to stop receiving messages, or if you suspect that the regID has
+been compromised. In general, though, once an app has a regID, you shouldn't need
+to change it.</p>
 
-<pre class="prettyprint pretty-java">...
-} else if (action.equals("com.example.gcm.intent.RETRY")) {
-    String token = intent.getStringExtra("token");
-    // make sure intent was generated by this class, not by a malicious app
-    if (TOKEN.equals(token)) {
-        String registrationId = // get from shared properties
-        if (registrationId != null) {
-        // last operation was attempt to unregister; send UNREGISTER intent again
-    } else {
-        // last operation was attempt to register; send REGISTER intent again
-    }
-}
-...</pre>
+<p>In particular, you should never unregister your app as a mechanism for
+logout or for switching between users, for the following reasons:</p>
 
-  <li> Create a new instance of <code>MyReceiver</code> in your activity:</li>
+<ul>
+  <li>A regID maps an app to a device. It isn't associated with a particular
+  logged in user. If you unregister and then re-register, GCM may return the same
+  ID or a different ID&mdash;there's no guarantee either way.</li>
 
-<pre class="prettyprint pretty-java">private final MyBroadcastReceiver mRetryReceiver = new MyBroadcastReceiver();
-</pre>
+  <li>Unregistration may take up to 5 minutes to propagate.</li>
+  <li>After unregistration, re-registration may again take up to 5 minutes to
+propagate. During this time messages may be rejected due to the state of being
+unregistered, and after all this, messages may still go to the wrong user.</li>
+</ul>
 
-  <li>In the activity's <code>onCreate()</code> method, register the new instance to receive the <code>com.example.gcm.intent.RETRY</code> intent:
-    <pre class="prettyprint pretty-java">...
-IntentFilter filter = new IntentFilter(&quot;com.example.gcm.intent.RETRY&quot;);
-filter.addCategory(getPackageName());
-registerReceiver(mRetryReceiver, filter);
-...</pre>
 
-<p class="note"><strong>Note:</strong> You must dynamically create a new instance of the broadcast receiver since the one defined by the manifest can only receive intents with the <code>com.google.android.c2dm.permission.SEND</code> permission. The permission <code>com.google.android.c2dm.permission.SEND</code> is a system permission and as such it cannot be granted to a regular application.</p>
+<p>The solution is to manage your own mapping between users, the regID, and
+individual messages:</p>
 
-</li>
+<ul>
+  <li>Your app server should maintain a mapping between the current user
+and the regID. This should include information about which user is supposed to
+receive a particular message.</li>
+  <li>The app running on the device should check to ensure that messages it
+receives match the logged in user.</li>
+</ul>
 
-  <li>In the activity's <code>onDestroy()</code> method, unregister the broadcast receiver:</li>
 
-<pre class="prettyprint pretty-java">unregisterReceiver(mRetryReceiver);</pre>
-</ol>
-<h2 id="unreg">How Unregistration Works</h2>
-<p>There are two ways to unregister a device from GCM: manually and automatically.</p>
-<p>An Android application can manually unregister itself by issuing a <code>com.google.android.c2dm.intent.UNREGISTER</code> intent, which is useful when the application offers a logoff feature (so it can unregister on logoff and register again on logon). See the <a href="gcm.html#unregistering">Architectural Overview</a> for more discussion of this topic. This is the sequence of events when an application unregisters itself:</p>
-<ol>
-  <li> The application issues a <code>com.google.android.c2dm.intent.UNREGISTER</code> intent, passing the package name as an extra.</li>
-  <li>When the GCM server is done with the unregistration, it sends a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent with the <code>unregistered</code> extra set.</li>
-  <li>The application then must contact the 3rd-party server so it can remove the registration ID.</li>
-  <li>The application should also clear its registration ID.
-  </li>
-</ol>
-<p>An application can be automatically unregistered after it is uninstalled from the device. However, this process does not happens right away, as Android does not provide an uninstall callback. What happens in this scenario is as follows:</p>
+<h3 id="unreg-how">How unregistration works</h3>
+
+<p>An application can be automatically unregistered after it is uninstalled from
+the device. However, this process does not happens right away, as Android does not
+provide an uninstall callback. What happens in this scenario is as follows:</p>
 <ol>
   <li>The end user uninstalls the application.</li>
   <li>The 3rd-party server sends a message to GCM server.</li>
   <li>The GCM server sends the message to the device.</li>
-  <li>The GCM client receives the message and queries Package Manager about whether there are broadcast receivers configured to receive it, which returns <code>false</code>. 
+  <li>The GCM client receives the message and queries Package Manager about
+whether there are broadcast receivers configured to receive it, which returns
+<code>false</code>.
 </li>
   <li>The GCM client informs the GCM server that the application was uninstalled.</li>
   <li>The GCM server marks the registration ID for deletion.</li>
@@ -184,9 +234,16 @@
   </li>
 </ol>
 
-<p class ="note"><strong>Note:</strong> The GCM client is the Google Cloud Messaging framework present on the device.</p>
+<p class ="note"><strong>Note:</strong> The GCM client is the Google Cloud
+Messaging framework present on the device.</p>
 
-<p>Note that it might take a while for the registration ID be completely removed from GCM. Thus it is possible that messages sent during step 7 above gets a valid message ID as response, even though the message will not be delivered to the device. Eventually, the registration ID will be removed and the server will get a <code>NotRegistered</code> error, without any further action being required from the 3rd-party server (this scenario happens frequently while an application is being developed and tested).</p>
+<p>Note that it might take a while for the registration ID be completely removed
+from GCM. Thus it is possible that messages sent during step 7 above gets a valid
+message ID as response, even though the message will not be delivered to the device.
+Eventually, the registration ID will be removed and the server will get a
+<code>NotRegistered</code> error, without any further action being required from
+the 3rd-party server (this scenario happens frequently while an application is
+being developed and tested).</p>
 
 <h2 id="collapsible">Send-to-Sync  vs. Messages with Payload</h2>
 
@@ -196,17 +253,45 @@
   <li>By default, it is stored by GCM for 4 weeks.</li>
 </ul>
 
-<p>But despite these similarities, messages can behave very differently depending on their particular settings. One major distinction between messages is whether they are collapsed (where each new message replaces the preceding message) or not collapsed (where each individual message is delivered). Every message sent in GCM is either a &quot;send-to-sync&quot; (collapsible) message or a &quot;message with payload&quot; (non-collapsible message). These concepts are described in more detail in the following sections.</p>
+<p>But despite these similarities, messages can behave very differently depending
+on their particular settings. One major distinction between messages is whether
+they are collapsed (where each new message replaces the preceding message) or not
+collapsed (where each individual message is delivered). Every message sent in GCM
+is either a &quot;send-to-sync&quot; (collapsible) message or a &quot;message with
+payload&quot; (non-collapsible message). These concepts are described in more
+detail in the following sections.</p>
 
 <h3 id="s2s"><strong>Send-to-sync messages</strong></h3>
 
-<p>A send-to-sync (collapsible) message is often a &quot;tickle&quot; that tells a mobile application to sync data from the server. For example, suppose you have an email application. When a user receives new email on the server, the server pings the mobile application with a &quot;New mail&quot; message. This tells the application to sync to the server to pick up the new email. The server might send this message multiple times as new mail continues to accumulate, before the application has had a chance to sync. But if the user has received 25 new emails, there's no need to preserve every &quot;New mail&quot; message. One is sufficient. Another example would be a sports application that updates users with the latest score. Only the most recent message is relevant, so it makes sense to have each new message replace the preceding message. </p>
+<p>A send-to-sync (collapsible) message is often a &quot;tickle&quot; that tells
+a mobile application to sync data from the server. For example, suppose you have
+an email application. When a user receives new email on the server, the server
+pings the mobile application with a &quot;New mail&quot; message. This tells the
+application to sync to the server to pick up the new email. The server might send
+this message multiple times as new mail continues to accumulate, before the application
+has had a chance to sync. But if the user has received 25 new emails, there's no
+need to preserve every &quot;New mail&quot; message. One is sufficient. Another
+example would be a sports application that updates users with the latest score.
+Only the most recent message is relevant, so it makes sense to have each new
+message replace the preceding message. </p>
 
-<p>The email and sports applications are cases where you would probably use the GCM <code>collapse_key</code> parameter. A <em>collapse key</em> is an arbitrary string that is used to collapse a group of like messages when the device is offline, so that only the most recent message gets sent to the client. For example, &quot;New mail,&quot; &quot;Updates available,&quot; and so on</p>
-<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server at any given time. In other words, the GCM server can simultaneously store 4 different send-to-sync messages, each with a different collapse key. If you exceed this number GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.</p>
+<p>The email and sports applications are cases where you would probably use the
+GCM <code>collapse_key</code> parameter. A <em>collapse key</em> is an arbitrary
+string that is used to collapse a group of like messages when the device is offline,
+so that only the most recent message gets sent to the client. For example,
+&quot;New mail,&quot; &quot;Updates available,&quot; and so on</p>
+<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server
+at any given time. In other words, the GCM server can simultaneously store 4
+different send-to-sync messages per device, each with a different collapse key.
+For example, Device A can have A1, A2, A3, and A4. Device B can have B1, B2, B3,
+and B4, and so on. If you exceed this number GCM will only keep 4 collapse keys, with no
+guarantees about which ones they will be.</p>
 
 <h3 id="payload">Messages with payload</h3>
-<p>Unlike a send-to-sync message, every &quot;message with payload&quot; (non-collapsible message) is delivered. The payload the message contains can be up to 4kb. For example, here is a JSON-formatted message in an IM application in which spectators are discussing a sporting event:</p>
+<p>Unlike a send-to-sync message, every &quot;message with payload&quot;
+(non-collapsible message) is delivered. The payload the message contains can be
+up to 4kb. For example, here is a JSON-formatted message in an IM application in
+which spectators are discussing a sporting event:</p>
 
 <pre class="prettyprint pretty-json">{
   "registration_id" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
@@ -217,19 +302,42 @@
   },
 }</pre>
 
-<p>A &quot;message with payload&quot; is not simply a &quot;ping&quot; to the mobile application to contact the server to fetch data. In the aforementioned IM application, for example, you would want to deliver every message, because every message has different content. To specify a non-collapsible message, you simply omit the <code>collapse_key</code> parameter. Thus GCM will send each message individually. Note that the order of delivery is not guaranteed.</p>
-<p>GCM will store up to 100 non-collapsible messages. After that, all messages are discarded from GCM, and a new message is created that tells the client how far behind it is. The message is delivered through a regular <code>com.google.android.c2dm.intent.RECEIVE</code> intent, with the following extras:</p>
+<p>A &quot;message with payload&quot; is not simply a &quot;ping&quot; to the
+mobile application to contact the server to fetch data. In the aforementioned IM
+application, for example, you would want to deliver every message, because every
+message has different content. To specify a non-collapsible message, you simply
+omit the <code>collapse_key</code> parameter. Thus GCM will send each message
+individually. Note that the order of delivery is not guaranteed.</p>
+
+<p>GCM will store up to 100 non-collapsible messages. After that, all messages
+are discarded from GCM, and a new message is created that tells the client how
+far behind it is. The message is delivered through a regular
+<code>com.google.android.c2dm.intent.RECEIVE</code> intent, with the following
+extras:</p>
 <ul>
-  <li> <code>message_type</code>&mdash;The value is always the string &quot;deleted_messages&quot;.</li>
-  <li><code>total_deleted</code>&mdash;The value  is a string with the number of deleted messages.</li>
+  <li> <code>message_type</code>&mdash;The value is always the string
+&quot;deleted_messages&quot;.</li>
+  <li><code>total_deleted</code>&mdash;The value  is a string with the number of
+deleted messages.</li>
 </ul>
-<p>The application should respond by syncing with the server to recover the discarded messages. </p>
+<p>The application should respond by syncing with the server to recover the
+discarded messages. </p>
 
 <h3 id="which">Which should I use?</h3>
-  <p>If your application does not need to use non-collapsible messages, collapsible messages are a better choice from a performance standpoint, because they put less of a burden on the device battery.</p>
+  <p>If your application does not need to use non-collapsible messages, collapsible
+messages are a better choice from a performance standpoint, because they put less
+of a burden on the device battery. However, if you use collapsible messages, remember that
+<strong>GCM only allows a maximum of 4 different collapse keys to be used by the GCM server
+per device at any given time</strong>. You must not exceed this number, or it could cause
+unpredictable consequences.</p>
 
 <h2 dir="ltr" id="ttl">Setting an Expiration Date for a Message</h2>
-<p>The Time to Live (TTL) feature lets  the sender  specify the maximum lifespan of a message using the <code>time_to_live</code> parameter in the send request. The value of this parameter must be a duration from 0 to 2,419,200 seconds, and it corresponds to the maximum period of time for which GCM will store and try to deliver the message. Requests that don't contain this field default to the maximum period of 4 weeks.</p>
+<p>The Time to Live (TTL) feature lets  the sender  specify the maximum lifespan
+of a message using the <code>time_to_live</code> parameter in the send request.
+The value of this parameter must be a duration from 0 to 2,419,200 seconds, and
+it corresponds to the maximum period of time for which GCM will store and try to
+deliver the message. Requests that don't contain this field default to the maximum
+period of 4 weeks.</p>
 <p>Here are some possible uses for this feature:</p>
 <ul>
   <li>Video chat incoming calls</li>
@@ -237,9 +345,29 @@
   <li>Calendar events</li>
 </ul>
 <h3 id="bg">Background </h3>
-<p>GCM will usually deliver messages immediately after they are sent. However, this might not always be possible. For example, the device could be turned off, offline, or otherwise unavailable. In other cases, the sender itself might request that messages not be delivered until the device becomes active by using the <code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages to prevent an application from consuming excessive resources and negatively impacting battery life.</p>
-<p>When this happens, GCM will store the message and deliver it as soon as it's feasible. While this is fine in most cases, there are some applications for which a late message might as well never be delivered. For example, if the message is an incoming call or video chat notification, it will only be meaningful for a small period of time before the call is terminated. Or if the message is an invitation to an event, it will be useless if received after the event has ended.</p>
-<p>Another advantage of specifying the expiration date for a message is that GCM will never throttle messages with a <code>time_to_live</code> value of 0 seconds. In other words, GCM will guarantee best effort for messages that must be delivered &quot;now or never.&quot; Keep in mind that a <code>time_to_live</code> value of 0 means messages that can't be delivered immediately will be discarded. However, because such messages are never stored, this provides the best latency for sending notifications.</p>
+<p>GCM will usually deliver messages immediately after they are sent. However,
+this might not always be possible. For example, the device could be turned off,
+offline, or otherwise unavailable. In other cases, the sender itself might request
+that messages not be delivered until the device becomes active by using the
+<code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages
+to prevent an application from consuming excessive resources and negatively
+impacting battery life.</p>
+
+<p>When this happens, GCM will store the message and deliver it as soon as it's
+feasible. While this is fine in most cases, there are some applications for which
+a late message might as well never be delivered. For example, if the message is
+an incoming call or video chat notification, it will only be meaningful for a
+small period of time before the call is terminated. Or if the message is an
+invitation to an event, it will be useless if received after the event has ended.</p>
+
+<p>Another advantage of specifying the expiration date for a message is that GCM
+will never throttle messages with a <code>time_to_live</code> value of 0 seconds.
+In other words, GCM will guarantee best effort for messages that must be delivered
+&quot;now or never.&quot; Keep in mind that a <code>time_to_live</code> value of
+0 means messages that can't be delivered immediately will be discarded. However,
+because such messages are never stored, this provides the best latency for
+sending notifications.</p>
+
 <p>Here is an example of a JSON-formatted request that includes TTL:</p>
 <pre class="prettyprint pretty-json">
 {
@@ -256,9 +384,23 @@
 
 
 <h2 id="multi-senders">Receiving Messages from Multiple Senders</h2>
-<p>GCM allows multiple parties to send messages to the same application. For example, suppose your application is an articles aggregator with multiple contributors, and you want each of them to be able to send a message when they publish a new article. This message might contain a URL so that the application can download the article. Instead of having to centralize all sending activity in one location, GCM gives you the ability to let each of these contributors send its own messages.</p>
-<p>To make this possible, all you need to do is have each sender generate its own project number. Then include those IDs in the sender field, separated by commas, when requesting a registration. Finally, share the registration ID with your partners, and they'll be able to send messages to your application using their own authentication keys.</p>
-<p>This code snippet illustrates this feature. Senders are passed as an intent extra in a comma-separated list:</p>
+
+<p>GCM allows multiple parties to send messages to the same application. For
+example, suppose your application is an articles aggregator with multiple
+contributors, and you want each of them to be able to send a message when they
+publish a new article. This message might contain a URL so that the application
+can download the article. Instead of having to centralize all sending activity in
+one location, GCM gives you the ability to let each of these contributors send
+its own messages.</p>
+
+<p>To make this possible, all you need to do is have each sender generate its own
+project number. Then include those IDs in the sender field, separated by commas,
+when requesting a registration. Finally, share the registration ID with your
+partners, and they'll be able to send messages to your application using their
+own authentication keys.</p>
+<p>This code snippet illustrates this feature. Senders are passed as an intent
+extra in a comma-separated list:</p>
+
 <pre class="prettyprint pretty-java">Intent intent = new Intent(GCMConstants.INTENT_TO_GCM_REGISTRATION);
 intent.setPackage(GSF_PACKAGE);
 intent.putExtra(GCMConstants.EXTRA_APPLICATION_PENDING_INTENT,
@@ -269,4 +411,3 @@
  </pre>
 
 <p>Note that there is limit of 100 multiple senders.</p>
- 
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 0cadbd2..d2177ca 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -1,93 +1,96 @@
-page.title=GCM Cloud Connection Server
+page.title=GCM Cloud Connection Server (XMPP)
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Quickview</h2>
-
-<ul>
-<li>Get an introduction to key CCS terms and concepts.</li>
-<li>Learn how to send and receive both upstream and downstream messages in CCS.</li>
-</ul>
-
 
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#gcm">CCS vs. GCM HTTP</a> </li>
   <li><a href="#usage">How to Use CCS</a>
-    <ol>
-      <li><a href="#send_msg">Sending Messages</a></li>
-      <li><a href="#format">Message Format</a></li>
-      <li><a href="#msg_examples">Message Examples</a></li>
+    <ol class="toc">
+      <li><a href="#auth">Authentication</a></li>
+      </ol>
+      </li>
+    <li><a href="#format">Message Format</a>
+      <ol class="toc">
+        <li><a href="#request">Request format</a></li>
+        <li><a href="#response">Response format</a></li>
+      </ol>
+      </li>
+  <li><a href="#upstream">Upstream Messages</a> </li>
+  <li><a href="#flow">Flow Control</a> </li>
+  <li><a href="#implement">Implementing an XMPP-based App Server</a>
+    <ol class="toc">
+      <li><a href="#smack">Java sample using the Smack library</a></li>
+      <li><a href="#python">Python sample</a></li>
     </ol>
   </li>
-  <li><a href="#flow">Flow Control</a> </li>
 </ol>
 
 <h2>See Also</h2>
 
 <ol class="toc">
-<li><a href="{@docRoot}google/play-services/gcm/gs.html">Getting Started</a></li>
-<li><a href="https://services.google.com/fb/forms/gcm/" class="external-link" target="_android">CCS and User Notifications Signup Form</a></li>
+<li><a href="{@docRoot}google/gcm/http.html">HTTP</a></li>
+<li><a href="{@docRoot}google/gcm/gs.html">Getting Started</a></li>
+<li><a href="{@docRoot}google/gcm/server.html">Implementing GCM Server</a></li>
+<li><a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a></li>
+<li><a href="https://services.google.com/fb/forms/gcm/" class="external-link"
+target="_android">CCS and User Notifications Signup Form</a></li>
 </ol>
 
 </div>
 </div>
 
-<p class="note"><strong>Note:</strong> To try out this feature, sign up using <a href="https://services.google.com/fb/forms/gcm/">this form</a>.</p>
+<p class="note"><strong>Note:</strong> To try out this feature, sign up using
+<a href="https://services.google.com/fb/forms/gcm/">this form</a>.</p>
 
-<p>The GCM Cloud Connection Server (CCS) allows third party servers to communicate with Android devices by  establishing a persistent TCP connection with Google servers using the XMPP protocol. This communication is asynchronous and bidirectional.</p>
-<p>You can continue to use the HTTP request mechanism to send messages to GCM servers, side-by-side with CCS which uses XMPP. Some of the benefits of CCS include:</p>
+<p>The GCM Cloud Connection Server (CCS) is a connection server based on XMPP.
+CCS allows 3rd-party app servers (which you're
+responsible for implementing) to communicate
+with Android devices by  establishing a persistent TCP connection with Google
+servers using the XMPP protocol. This communication is asynchronous and bidirectional.</p>
+<p>You can continue to use the HTTP request mechanism to send messages to GCM
+servers, side-by-side with CCS which uses XMPP. Some of the benefits of CCS include:</p>
 <ul>
-  <li>The asynchronous nature of XMPP allows you to send more messages with fewer resources.</li>
-  <li>Communication is bidirectional&mdash;not only can the server send messages to the device, but the device can send messages back to the server.</li>
-<li>You can send messages back using the same connection used for receiving, thereby improving battery life.</li>
+  <li>The asynchronous nature of XMPP allows you to send more messages with fewer
+resources.</li>
+  <li>Communication is bidirectional&mdash;not only can the server send messages
+to the device, but the device can send messages back to the server.</li>
+<li>You can send messages back using the same connection used for receiving,
+thereby improving battery life.</li>
 </ul>
 
-<p>The upstream messaging (device-to-cloud) feature of CCS is part of the Google Play services platform. Upstream messaging is available through the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. To use upstream messaging and the new streamlined registration process, you must <a href="{@docRoot}google/play-services/setup.html">set up</a> the Google Play services SDK.</p>
+<p>The upstream messaging (device-to-cloud) feature of CCS is part of the Google
+Play services platform. Upstream messaging is available through the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+APIs. For examples, see
+<a href="#implement">Implementing an XMPP-based App Server</a>.</p>
 
-<p class="note"><strong>Note:</strong> For an example of an XMPP server, see <a href="server.html#xmpp">GCM Server</a>.
+<p class="note"><strong>Note:</strong> See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+parameters and which connection server(s) supports them.</p>
 
-<h2 id="gcm">CCS vs. GCM HTTP</h2>
-
-<p>CCS messaging differs from GCM HTTP messaging in the following ways:</p>
-<ul>
-  <li>Upstream/Downstream messages
-    <ul>
-      <li>GCM HTTP: Downstream only: cloud-to-device. </li>
-      <li>CCS: Upstream and downstream (device-to-cloud, cloud-to-device). </li>
-    </ul>
-  </li>
-  <li>Asynchronous messaging
-    <ul>
-      <li>GCM HTTP: 3rd-party servers send messages as HTTP POST requests and wait for a response. This mechanism is synchronous and causes the sender to block before sending another message.</li>
-      <li>CCS: 3rd-party servers connect to Google infrastructure using a persistent XMPP connection and send/receive messages to/from all their devices at full line speed. CCS sends acknowledgements or failure notifications (in the form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
-    </ul>
-  </li>
-
-  <li>JSON
-    <ul>
-      <li>GCM HTTP: JSON messages sent as HTTP POST.</li>
-      <li>CCS: JSON messages encapsulated in XMPP messages.</li>
-    </ul>
-  </li>
-</ul>
-<p>This document describes how to use CCS. For general concepts and information on how to use GCM HTTP, see the <a href="gcm.html">GCM Architectural Overview</a>.</p>
 
 <h2 id="usage">How to Use CCS</h2>
 
-<p>GCM Cloud Connection Server (CCS) is an XMPP endpoint, running on {@code http://gcm.googleapis.com} port 5235.</p>
+<p>GCM Cloud Connection Server (CCS) is an XMPP endpoint, running on
+{@code http://gcm.googleapis.com} port 5235.</p>
 
-<p>CCS requires a Transport Layer Security (TLS) connection. That means the  XMPP client must initiate a TLS connection.
-For example in smack, you would call {@code setSocketFactory(SSLSocketFactory)}, similar to “old style SSL” XMPP connections and https.</p>
+<p>CCS requires a Transport Layer Security (TLS) connection. That means the  XMPP
+client must initiate a TLS connection.
+For example in Java, you would call {@code setSocketFactory(SSLSocketFactory)}.</p>
 
-<p>CCS requires a SASL PLAIN authentication mechanism using {@code &lt;your_GCM_Sender_Id&gt;&#64;gcm.googleapis.com} (GCM sender ID) and the API key as the password, where the sender ID and API key are the same as described in <a href="gs.html">Getting Started</a>.</p>
+<p>CCS requires a SASL PLAIN authentication mechanism using
+{@code &lt;your_GCM_Sender_Id&gt;&#64;gcm.googleapis.com} (GCM sender ID) and the
+API key as the password, where the sender ID and API key are the same as described
+in <a href="gs.html">Getting Started</a>.</p>
 
 <p> You can use most XMPP libraries to interact with CCS.</p>
 
-<h3 id="send_msg">Sending messages</h3>
+<h3 id="auth">Authentication</h3>
 
 <p>The following snippets illustrate how to perform authentication in CCS.</p>
 <h4>Client</h4>
@@ -108,13 +111,13 @@
 <h4>Client</h4>
 <pre>&lt;auth mechanism=&quot;PLAIN&quot;
 xmlns=&quot;urn:ietf:params:xml:ns:xmpp-sasl&quot;&gt;MTI2MjAwMzQ3OTMzQHByb2plY3RzLmdjbS5hb
-mRyb2lkLmNvbQAxMjYyMDAzNDc5FzNAcHJvamVjdHMtZ2EtLmFuZHJvaWQuY29tAEFJe
 mFTeUIzcmNaTmtmbnFLZEZiOW1oekNCaVlwT1JEQTJKV1d0dw==&lt;/auth&gt;
 </pre>
+
 <h4>Server</h4>
 <pre>&lt;success xmlns=&quot;urn:ietf:params:xml:ns:xmpp-sasl&quot;/&gt;</pre>
 
-<h3 id="format">Message Format</h3>
+<h2 id="format">Message Format</h2>
 <p>CCS uses normal XMPP <code>&lt;message&gt;</code> stanzas. The body of the message must be:
 </p>
 <pre>
@@ -123,25 +126,42 @@
 &lt;/gcm&gt;
 </pre>
 
-<p>The JSON payload for server-to-device is similar to what the GCM http endpoint uses, with these exceptions:</p>
+<p>The JSON payload for server-to-device is similar to what the GCM http endpoint
+uses, with these exceptions:</p>
 <ul>
   <li>There is no support for multiple recipients.</li>
   <li>{@code to} is used instead of {@code registration_ids}.</li>
-  <li>CCS adds the field {@code message_id}, which is required. This ID uniquely identifies the message in an XMPP connection. The ACK or NACK from CCS uses the {@code message_id} to identify a message sent from 3rd-party servers to CCS. Therefore, it's important that this {@code message_id} not only be unique, but always present.</li>
+  <li>CCS adds the field {@code message_id}, which is required. This ID uniquely
+identifies the message in an XMPP connection. The ACK or NACK from CCS uses the
+{@code message_id} to identify a message sent from 3rd-party app servers to CCS.
+Therefore, it's important that this {@code message_id} not only be unique, but
+always present.</li>
 
-  <li>For ACK/NACK messages that are special control messages, you also need to include a {@code message_type} field in the JSON message. For example:
+<li>For ACK/NACK messages that are special control messages, you also need to
+include a {@code message_type} field in the JSON message. The value can be either
+'ack' or 'nack'. For example:
 
-<pre>message_type = ('ack' OR 'nack');</pre>
+<pre>message_type = ('ack');</pre>
   </li>
 </ul>
-<p>For each message a device sends to the server, you need to send an ACK message. You never need to send a NACK message. If you don't send an ACK for a message, CCS will just resend it.
+<p>For each device message your app server receives from CCS, it needs to send
+an ACK message.
+It never needs to send a NACK message. If you don't send an ACK for a message,
+CCS will just resend it.
 </p>
-<p>CCS also sends an ACK or NACK for each server-to-device message. If you do not receive either, it means that the TCP connection was closed in the middle of the operation and your server needs to resend the messages.
+<p>CCS also sends an ACK or NACK for each server-to-device message. If you do not
+receive either, it means that the TCP connection was closed in the middle of the
+operation and your server needs to resend the messages. See
+<a href="#flow">Flow Control</a> for details.
 </p>
 
-<h3 id="msg_examples">Message Examples</h3>
+<p class="note"><strong>Note:</strong> See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+parameters and which connection server(s) supports them.</p>
 
-<p>Here is an XMPP stanza containing the JSON message from a 3rd-party server to CCS:
+<h3 id="request">Request format</h3>
+
+<p>Here is an XMPP stanza containing the JSON message from a 3rd-party app server to CCS:
 
 </p>
 <pre>&lt;message id=&quot;&quot;&gt;
@@ -160,7 +180,15 @@
 &lt;/message&gt;
 </pre>
 
-<p>Here is an XMPP stanza containing the ACK/NACK message from CCS to 3rd-party server:
+<h3 id="response">Response format</h3>
+
+<p>A CCS response can have 3 possible forms. The first one is a regular 'ack'
+message. But when the response contains an error, there are 2
+different forms the message can take, described below.</p>
+
+<h4 id="ack">ACK message</h4>
+
+<p>Here is an XMPP stanza containing the ACK/NACK message from CCS to 3rd-party app server:
 </p>
 <pre>&lt;message id=&quot;&quot;&gt;
   &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
@@ -171,24 +199,138 @@
   }
   &lt;/gcm&gt;
 &lt;/message&gt;
+</pre>
 
-&lt;message id=&quot;&quot;&gt;
-  &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
+<h4 id="nack">NACK message</h4>
+
+<p>A NACK error is a regular XMPP message in which the {@code message_type} status
+message is &quot;nack&quot;. A NACK message contains:</p>
+<ul>
+<li>Nack error code.</li>
+<li>Nack error description.</li>
+</ul>
+
+<p>Below are some examples.</p>
+
+<p>Bad registration:</p>
+<pre>&lt;message&gt;
+  &lt;data:gcm xmlns:data=&quot;google:mobile:data&quot;&gt;
   {
-      &quot;from&quot;:&quot;REGID&quot;,
-      &quot;message_id&quot;:&quot;m-1366082849205&quot;
-      &quot;error&quot;: ERROR_CODE,
-      &quot;message_type&quot;:&quot;nack&quot;
+    &quot;error&quot;:&quot;BAD_REGISTRATION&quot;,  // error code
+    &quot;message_id&quot;:&quot;msgId1&quot;,
+    &quot;from&quot;:&quot;PA91bHFOtaQGSwupt5l1og&quot;,
+    &quot;message_type&quot;:&quot;nack&quot;
   }
+  &lt;/data:gcm&gt;
+&lt;/message&gt;</pre>
+
+<p>Invalid "time to live":</p>
+
+<pre>&lt;message&gt;
+  &lt;data:gcm xmlns:data=&quot;google:mobile:data&quot;&gt;
+  {
+     &quot;error&quot;:&quot;InvalidJson : INVALID_TTL : Invalid value (-1) for \&quot;time_to_live\&quot;: must be between 0 and \&quot;2419200\&quot;\n&quot;,
+     &quot;message_id&quot;:&quot;msgId1&quot;,
+     &quot;from&quot;:&quot;APA91bHFOtaQGSwupt5l1og&quot;,
+     &quot;message_type&quot;:&quot;nack&quot;
+  }
+  &lt;/data:gcm&gt;
+&lt;/message&gt;</pre>
+
+<p>JSON type error:</p>
+
+<pre>&lt;message&gt;
+  &lt;data:gcm xmlns:data=&quot;google:mobile:data&quot;&gt;
+  {
+     &quot;error&quot;:&quot;InvalidJson : JSON_TYPE_ERROR : Field \&quot;delay_while_idle\&quot; must be a JSON java.lang.Boolean: not-boolean-user-supplied-value\n&quot;,
+     &quot;message_id&quot;:&quot;msgId1&quot;,
+     &quot;from&quot;:&quot;APA91bHFOtaQGSwupt5l1og&quot;,
+     &quot;message_type&quot;:&quot;nack&quot;
+  }
+  &lt;/data:gcm&gt;
+&lt;/message&gt;</pre>
+
+
+<p>The following table lists some of the more common NACK error codes.</p>
+
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> NACK error codes.</p>
+
+<table border="1">
+<tr>
+<th>Error Code</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>{@code BAD_REGISTRATION}</td>
+<td>The device has a registration ID, but it's invalid.</td>
+</tr>
+<tr>
+<td>{@code DEVICE_UNREGISTERED}</td>
+<td>The device is not registered.</td>
+</tr>
+<tr>
+<td>{@code INTERNAL_SERVER_ERROR}</td>
+<td>The server encountered an error while trying to process the request.</td>
+</tr>
+<tr>
+<td>{@code SERVICE_UNAVAILABLE}</td>
+<td>The CCS connection server is temporarily unavailable, try again later
+(using exponential backoff, etc.).</td>
+</tr>
+<tr>
+<td>{@code BAD_ACK}</td>
+<td>The ACK message is improperly formed.</td>
+</tr>
+<tr>
+<td>{@code AUTHENTICATION_FAILED}</td>
+<td>This is a 401 error indicating that there was an error authenticating the sender account.</td>
+</tr>
+<tr>
+<td>{@code INVALID_TTL}</td>
+<td>There was an error in the supplied "time to live" value.</td>
+</tr>
+<tr>
+<td>{@code JSON_TYPE_ERROR}</td>
+<td>There was an error in the supplied JSON data type.</td>
+</tr>
+</table>
+
+<h4 id="stanza">Stanza error</h4>
+
+<p>You can also get a stanza error in certain cases.
+A stanza error contains:</p>
+<ul>
+<li>Stanza error code.</li>
+<li>Stanza error description (free text).</li>
+</ul>
+<p>For example:</p>
+
+<pre>&lt;message id=&quot;3&quot; type=&quot;error&quot; to=&quot;123456789@gcm.googleapis.com/ABC&quot;&gt;
+  &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
+     {&quot;random&quot;: &quot;text&quot;}
   &lt;/gcm&gt;
+  &lt;error code=&quot;400&quot; type=&quot;modify&quot;&gt;
+    &lt;bad-request xmlns=&quot;urn:ietf:params:xml:ns:xmpp-stanzas&quot;/&gt;
+    &lt;text xmlns=&quot;urn:ietf:params:xml:ns:xmpp-stanzas&quot;&gt;
+      InvalidJson: JSON_PARSING_ERROR : Missing Required Field: message_id\n
+    &lt;/text&gt;
+  &lt;/error&gt;
 &lt;/message&gt;
 </pre>
 
-<h4>Upstream Messages</h4>
 
-<p>Using CCS and the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> API, you can send messages from a user's device to the cloud.</p>
+<h2 id="upstream">Upstream Messages</h2>
 
-<p>Here is how you send an upstream message using the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> API. For a complete example, see <a href="gs.html#gs_example">Getting Started</a>:</p>
+<p>Using CCS and the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+API, you can send messages from a user's device to the cloud.</p>
+
+<p>Here is how you send an upstream message using the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+API. For a complete example, see <a href="client.html">Implementing GCM Client</a>:</p>
 
 <pre>GoogleCloudMessaging gcm = GoogleCloudMessaging.get(context);
 String GCM_SENDER_ID = "Your-Sender-ID";
@@ -198,12 +340,15 @@
 // Bundle data consists of a key-value pair
 data.putString("hello", "world");
 // "time to live" parameter
+// This is optional. It specifies a value in seconds up to 4 weeks.
 int ttl = [0 seconds, 4 weeks]
 
 gcm.send(GCM_SENDER_ID + "&#64;gcm.googleapis.com", id, ttl, data);
 </pre>
 
-<p>This call generates the necessary XMPP stanza for sending the upstream message. The message goes from the app on the device to CCS to the 3rd-party server. The stanza has the following format:</p>
+<p>This call generates the necessary XMPP stanza for sending the upstream message.
+The message goes from the app on the device to CCS to the 3rd-party app server.
+The stanza has the following format:</p>
 
 <pre>&lt;message id=&quot;&quot;&gt;
   &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
@@ -219,7 +364,8 @@
   &lt;/gcm&gt;
 &lt;/message&gt;</pre>
 
-<p>Here is the format of the ACK expected by CCS from 3rd-party servers in response to the above message:</p>
+<p>Here is the format of the ACK expected by CCS from 3rd-party app servers in
+response to the above message:</p>
 
 <pre>&lt;message id=&quot;&quot;&gt;
   &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
@@ -231,13 +377,478 @@
   &lt;/gcm&gt;
 &lt;/message&gt;</pre>
 
-
 <h2 id="flow">Flow Control</h2>
 
-<p>Every message sent to CCS receives either an ACK or a NACK response. Messages that haven't received one of these responses are considered pending. If the pending message count reaches 1000, the 3rd-party server should stop sending new messages and wait for CCS to acknowledge some of the existing pending messages.</p>
+<p>Every message sent to CCS receives either an ACK or a NACK response. Messages
+that haven't received one of these responses are considered pending. If the pending
+message count reaches 1000, the 3rd-party app server should stop sending new messages
+and wait for CCS to acknowledge some of the existing pending messages as illustrated in
+figure 1:</p>
 
-<p>Conversely, to avoid overloading the 3rd-party server, CCS will stop sending if there are too many unacknowledged messages. Therefore, the 3rd-party server should "ACK" received messages as soon as possible to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party server should continue sending ACKs to avoid blocking delivery of new messages.</p>
+<img src="{@docRoot}images/gcm/CCS-ack.png">
 
-<p>ACKs are only valid within the context of one connection. If the connection is closed before a message can be ACKed, the 3rd-party server should wait for CCS to resend the message before ACKing it again.
+<p class="img-caption">
+  <strong>Figure 1.</strong> Message/ack flow.
 </p>
 
+<p>Conversely, to avoid overloading the 3rd-party app server, CCS will stop sending
+if there are too many unacknowledged messages. Therefore, the 3rd-party app server
+should "ACK" upstream messages, received from the client application via CCS, as soon as possible
+to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't
+apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party app server
+should continue sending ACKs for messages received from CCS to avoid blocking delivery of new
+upstream messages.</p>
+
+<p>ACKs are only valid within the context of one connection. If the connection is
+closed before a message can be ACKed, the 3rd-party app server should wait for CCS
+to resend the upstream message before ACKing it again. Similarly, all pending messages for which an
+ACK/NACK was not received from CCS before the connection was closed should be sent again.
+</p>
+
+<h2 id="implement">Implementing an XMPP-based App Server</h2>
+
+<p>This section gives examples of implementing an app server that works with CCS.
+Note that a full GCM implementation requires a client-side implementation, in
+addition to the server. For more information, see <a href="client.html">
+Implementing GCM Client</a>.</a>
+
+<h3 id="smack">Java sample using the Smack library</h3>
+
+<p>Here is a sample app server written in Java, using the
+<a href="http://www.igniterealtime.org/projects/smack/">Smack</a> library.</p>
+
+<pre>import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
+import org.jivesoftware.smack.ConnectionListener;
+import org.jivesoftware.smack.PacketInterceptor;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.DefaultPacketExtension;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.util.StringUtils;
+import org.json.simple.JSONValue;
+import org.json.simple.parser.ParseException;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.SSLSocketFactory;
+/**
+ * Sample Smack implementation of a client for GCM Cloud Connection Server.
+ *
+ * &lt;p&gt;For illustration purposes only.
+ */
+public class SmackCcsClient {
+
+  Logger logger = Logger.getLogger(&quot;SmackCcsClient&quot;);
+
+  public static final String GCM_SERVER = &quot;gcm.googleapis.com&quot;;
+  public static final int GCM_PORT = 5235;
+
+  public static final String GCM_ELEMENT_NAME = &quot;gcm&quot;;
+  public static final String GCM_NAMESPACE = &quot;google:mobile:data&quot;;
+
+  static Random random = new Random();
+  XMPPConnection connection;
+  ConnectionConfiguration config;
+
+  /**
+   * XMPP Packet Extension for GCM Cloud Connection Server.
+   */
+  class GcmPacketExtension extends DefaultPacketExtension {
+    String json;
+
+    public GcmPacketExtension(String json) {
+      super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
+      this.json = json;
+    }
+
+    public String getJson() {
+      return json;
+    }
+
+    &#64;Override
+    public String toXML() {
+      return String.format(&quot;&lt;%s xmlns=\&quot;%s\&quot;&gt;%s&lt;/%s&gt;&quot;, GCM_ELEMENT_NAME,
+          GCM_NAMESPACE, json, GCM_ELEMENT_NAME);
+    }
+
+    &#64;SuppressWarnings(&quot;unused&quot;)
+    public Packet toPacket() {
+      return new Message() {
+        // Must override toXML() because it includes a &lt;body&gt;
+        &#64;Override
+        public String toXML() {
+
+          StringBuilder buf = new StringBuilder();
+          buf.append(&quot;&lt;message&quot;);
+          if (getXmlns() != null) {
+            buf.append(&quot; xmlns=\&quot;&quot;).append(getXmlns()).append(&quot;\&quot;&quot;);
+          }
+          if (getLanguage() != null) {
+            buf.append(&quot; xml:lang=\&quot;&quot;).append(getLanguage()).append(&quot;\&quot;&quot;);
+          }
+          if (getPacketID() != null) {
+            buf.append(&quot; id=\&quot;&quot;).append(getPacketID()).append(&quot;\&quot;&quot;);
+          }
+          if (getTo() != null) {
+            buf.append(&quot; to=\&quot;&quot;).append(StringUtils.escapeForXML(getTo())).append(&quot;\&quot;&quot;);
+          }
+          if (getFrom() != null) {
+            buf.append(&quot; from=\&quot;&quot;).append(StringUtils.escapeForXML(getFrom())).append(&quot;\&quot;&quot;);
+          }
+          buf.append(&quot;&gt;&quot;);
+          buf.append(GcmPacketExtension.this.toXML());
+          buf.append(&quot;&lt;/message&gt;&quot;);
+          return buf.toString();
+        }
+      };
+    }
+  }
+
+  public SmackCcsClient() {
+    // Add GcmPacketExtension
+    ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
+        GCM_NAMESPACE, new PacketExtensionProvider() {
+
+      &#64;Override
+      public PacketExtension parseExtension(XmlPullParser parser)
+          throws Exception {
+        String json = parser.nextText();
+        GcmPacketExtension packet = new GcmPacketExtension(json);
+        return packet;
+      }
+    });
+  }
+
+  /**
+   * Returns a random message id to uniquely identify a message.
+   *
+   * &lt;p&gt;Note:
+   * This is generated by a pseudo random number generator for illustration purpose,
+   * and is not guaranteed to be unique.
+   *
+   */
+  public String getRandomMessageId() {
+    return &quot;m-&quot; + Long.toString(random.nextLong());
+  }
+
+  /**
+   * Sends a downstream GCM message.
+   */
+  public void send(String jsonRequest) {
+    Packet request = new GcmPacketExtension(jsonRequest).toPacket();
+    connection.sendPacket(request);
+  }
+
+  /**
+   * Handles an upstream data message from a device application.
+   *
+   * &lt;p&gt;This sample echo server sends an echo message back to the device.
+   * Subclasses should override this method to process an upstream message.
+   */
+  public void handleIncomingDataMessage(Map&lt;String, Object&gt; jsonObject) {
+    String from = jsonObject.get(&quot;from&quot;).toString();
+
+    // PackageName of the application that sent this message.
+    String category = jsonObject.get(&quot;category&quot;).toString();
+
+    // Use the packageName as the collapseKey in the echo packet
+    String collapseKey = &quot;echo:CollapseKey&quot;;
+    &#64;SuppressWarnings(&quot;unchecked&quot;)
+    Map&lt;String, String&gt; payload = (Map&lt;String, String&gt;) jsonObject.get(&quot;data&quot;);
+    payload.put(&quot;ECHO&quot;, &quot;Application: &quot; + category);
+
+    // Send an ECHO response back
+    String echo = createJsonMessage(from, getRandomMessageId(), payload, collapseKey, null, false);
+    send(echo);
+  }
+
+  /**
+   * Handles an ACK.
+   *
+   * &lt;p&gt;By default, it only logs a {@code INFO} message, but subclasses could override it to
+   * properly handle ACKS.
+   */
+  public void handleAckReceipt(Map&lt;String, Object&gt; jsonObject) {
+    String messageId = jsonObject.get(&quot;message_id&quot;).toString();
+    String from = jsonObject.get(&quot;from&quot;).toString();
+    logger.log(Level.INFO, &quot;handleAckReceipt() from: &quot; + from + &quot;, messageId: &quot; + messageId);
+  }
+
+  /**
+   * Handles a NACK.
+   *
+   * &lt;p&gt;By default, it only logs a {@code INFO} message, but subclasses could override it to
+   * properly handle NACKS.
+   */
+  public void handleNackReceipt(Map&lt;String, Object&gt; jsonObject) {
+    String messageId = jsonObject.get(&quot;message_id&quot;).toString();
+    String from = jsonObject.get(&quot;from&quot;).toString();
+    logger.log(Level.INFO, &quot;handleNackReceipt() from: &quot; + from + &quot;, messageId: &quot; + messageId);
+  }
+
+  /**
+   * Creates a JSON encoded GCM message.
+   *
+   * &#64;param to RegistrationId of the target device (Required).
+   * &#64;param messageId Unique messageId for which CCS will send an &quot;ack/nack&quot; (Required).
+   * &#64;param payload Message content intended for the application. (Optional).
+   * &#64;param collapseKey GCM collapse_key parameter (Optional).
+   * &#64;param timeToLive GCM time_to_live parameter (Optional).
+   * &#64;param delayWhileIdle GCM delay_while_idle parameter (Optional).
+   * &#64;return JSON encoded GCM message.
+   */
+  public static String createJsonMessage(String to, String messageId, Map&lt;String, String&gt; payload,
+      String collapseKey, Long timeToLive, Boolean delayWhileIdle) {
+    Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
+    message.put(&quot;to&quot;, to);
+    if (collapseKey != null) {
+      message.put(&quot;collapse_key&quot;, collapseKey);
+    }
+    if (timeToLive != null) {
+      message.put(&quot;time_to_live&quot;, timeToLive);
+    }
+    if (delayWhileIdle != null &amp;&amp; delayWhileIdle) {
+      message.put(&quot;delay_while_idle&quot;, true);
+    }
+    message.put(&quot;message_id&quot;, messageId);
+    message.put(&quot;data&quot;, payload);
+    return JSONValue.toJSONString(message);
+  }
+
+  /**
+   * Creates a JSON encoded ACK message for an upstream message received from an application.
+   *
+   * &#64;param to RegistrationId of the device who sent the upstream message.
+   * &#64;param messageId messageId of the upstream message to be acknowledged to CCS.
+   * &#64;return JSON encoded ack.
+   */
+  public static String createJsonAck(String to, String messageId) {
+    Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
+    message.put(&quot;message_type&quot;, &quot;ack&quot;);
+    message.put(&quot;to&quot;, to);
+    message.put(&quot;message_id&quot;, messageId);
+    return JSONValue.toJSONString(message);
+  }
+
+  /**
+   * Connects to GCM Cloud Connection Server using the supplied credentials.
+   *
+   * &#64;param username GCM_SENDER_ID&#64;gcm.googleapis.com
+   * &#64;param password API Key
+   * &#64;throws XMPPException
+   */
+  public void connect(String username, String password) throws XMPPException {
+    config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
+    config.setSecurityMode(SecurityMode.enabled);
+    config.setReconnectionAllowed(true);
+    config.setRosterLoadedAtLogin(false);
+    config.setSendPresence(false);
+    config.setSocketFactory(SSLSocketFactory.getDefault());
+
+    // NOTE: Set to true to launch a window with information about packets sent and received
+    config.setDebuggerEnabled(true);
+
+    // -Dsmack.debugEnabled=true
+    XMPPConnection.DEBUG_ENABLED = true;
+
+    connection = new XMPPConnection(config);
+    connection.connect();
+
+    connection.addConnectionListener(new ConnectionListener() {
+
+      &#64;Override
+      public void reconnectionSuccessful() {
+        logger.info(&quot;Reconnecting..&quot;);
+      }
+
+      &#64;Override
+      public void reconnectionFailed(Exception e) {
+        logger.log(Level.INFO, &quot;Reconnection failed.. &quot;, e);
+      }
+
+      &#64;Override
+      public void reconnectingIn(int seconds) {
+        logger.log(Level.INFO, &quot;Reconnecting in %d secs&quot;, seconds);
+      }
+
+      &#64;Override
+      public void connectionClosedOnError(Exception e) {
+        logger.log(Level.INFO, &quot;Connection closed on error.&quot;);
+      }
+
+      &#64;Override
+      public void connectionClosed() {
+        logger.info(&quot;Connection closed.&quot;);
+      }
+    });
+
+    // Handle incoming packets
+    connection.addPacketListener(new PacketListener() {
+
+      &#64;Override
+      public void processPacket(Packet packet) {
+        logger.log(Level.INFO, &quot;Received: &quot; + packet.toXML());
+        Message incomingMessage = (Message) packet;
+        GcmPacketExtension gcmPacket =
+            (GcmPacketExtension) incomingMessage.getExtension(GCM_NAMESPACE);
+        String json = gcmPacket.getJson();
+        try {
+          &#64;SuppressWarnings(&quot;unchecked&quot;)
+          Map&lt;String, Object&gt; jsonObject =
+              (Map&lt;String, Object&gt;) JSONValue.parseWithException(json);
+
+          // present for &quot;ack&quot;/&quot;nack&quot;, null otherwise
+          Object messageType = jsonObject.get(&quot;message_type&quot;);
+
+          if (messageType == null) {
+            // Normal upstream data message
+            handleIncomingDataMessage(jsonObject);
+
+            // Send ACK to CCS
+            String messageId = jsonObject.get(&quot;message_id&quot;).toString();
+            String from = jsonObject.get(&quot;from&quot;).toString();
+            String ack = createJsonAck(from, messageId);
+            send(ack);
+          } else if (&quot;ack&quot;.equals(messageType.toString())) {
+            // Process Ack
+            handleAckReceipt(jsonObject);
+          } else if (&quot;nack&quot;.equals(messageType.toString())) {
+            // Process Nack
+            handleNackReceipt(jsonObject);
+          } else {
+            logger.log(Level.WARNING, &quot;Unrecognized message type (%s)&quot;,
+                messageType.toString());
+          }
+        } catch (ParseException e) {
+          logger.log(Level.SEVERE, &quot;Error parsing JSON &quot; + json, e);
+        } catch (Exception e) {
+          logger.log(Level.SEVERE, &quot;Couldn't send echo.&quot;, e);
+        }
+      }
+    }, new PacketTypeFilter(Message.class));
+
+
+    // Log all outgoing packets
+    connection.addPacketInterceptor(new PacketInterceptor() {
+      &#64;Override
+      public void interceptPacket(Packet packet) {
+        logger.log(Level.INFO, &quot;Sent: {0}&quot;,  packet.toXML());
+      }
+    }, new PacketTypeFilter(Message.class));
+
+    connection.login(username, password);
+  }
+
+  public static void main(String [] args) {
+    final String userName = &quot;Your GCM Sender Id&quot; + &quot;&#64;gcm.googleapis.com&quot;;
+    final String password = &quot;API Key&quot;;
+
+    SmackCcsClient ccsClient = new SmackCcsClient();
+
+    try {
+      ccsClient.connect(userName, password);
+    } catch (XMPPException e) {
+      e.printStackTrace();
+    }
+
+    // Send a sample hello downstream message to a device.
+    String toRegId = &quot;RegistrationIdOfTheTargetDevice&quot;;
+    String messageId = ccsClient.getRandomMessageId();
+    Map&lt;String, String&gt; payload = new HashMap&lt;String, String&gt;();
+    payload.put(&quot;Hello&quot;, &quot;World&quot;);
+    payload.put(&quot;CCS&quot;, &quot;Dummy Message&quot;);
+    payload.put(&quot;EmbeddedMessageId&quot;, messageId);
+    String collapseKey = &quot;sample&quot;;
+    Long timeToLive = 10000L;
+    Boolean delayWhileIdle = true;
+    ccsClient.send(createJsonMessage(toRegId, messageId, payload, collapseKey,
+        timeToLive, delayWhileIdle));
+  }
+}</pre>
+<h3 id="python">Python sample</h3>
+
+<p>Here is an example of a CCS app server written in Python. This sample echo
+server sends an initial message, and for every upstream message received, it sends
+a dummy response back to the application that sent the upstream message. This
+example illustrates how to connect, send, and receive GCM messages using XMPP. It
+shouldn't be used as-is on a production deployment.</p>
+
+<pre>
+#!/usr/bin/python
+import sys, json, xmpp, random, string
+
+SERVER = 'gcm.googleapis.com'
+PORT = 5235
+USERNAME = "Your GCM Sender Id"
+PASSWORD = "API Key"
+REGISTRATION_ID = "Registration Id of the target device"
+
+unacked_messages_quota = 1000
+send_queue = []
+
+# Return a random alphanumerical id
+def random_id():
+  rid = ''
+  for x in range(8): rid += random.choice(string.ascii_letters + string.digits)
+  return rid
+
+def message_callback(session, message):
+  global unacked_messages_quota
+  gcm = message.getTags('gcm')
+  if gcm:
+    gcm_json = gcm[0].getData()
+    msg = json.loads(gcm_json)
+    if not msg.has_key('message_type'):
+      # Acknowledge the incoming message immediately.
+      send({'to': msg['from'],
+            'message_type': 'ack',
+            'message_id': msg['message_id']})
+      # Queue a response back to the server.
+      if msg.has_key('from'):
+        # Send a dummy echo response back to the app that sent the upstream message.
+        send_queue.append({'to': msg['from'],
+                           'message_id': random_id(),
+                           'data': {'pong': 1}})
+    elif msg['message_type'] == 'ack' or msg['message_type'] == 'nack':
+      unacked_messages_quota += 1
+
+def send(json_dict):
+  template = (&quot;&lt;message&gt;&lt;gcm xmlns='google:mobile:data'&gt;{1}&lt;/gcm&gt;&lt;/message&gt;&quot;)
+  client.send(xmpp.protocol.Message(
+      node=template.format(client.Bind.bound[0], json.dumps(json_dict))))
+
+def flush_queued_messages():
+  global unacked_messages_quota
+  while len(send_queue) and unacked_messages_quota &gt; 0:
+    send(send_queue.pop(0))
+    unacked_messages_quota -= 1
+
+client = xmpp.Client('gcm.googleapis.com', debug=['socket'])
+client.connect(server=(SERVER,PORT), secure=1, use_srv=False)
+auth = client.auth(USERNAME, PASSWORD)
+if not auth:
+  print 'Authentication failed!'
+  sys.exit(1)
+
+client.RegisterHandler('message', message_callback)
+
+send_queue.append({'to': REGISTRATION_ID,
+                   'message_id': 'reg_id',
+                   'data': {'message_destination': 'RegId',
+                            'message_id': random_id()}})
+
+while True:
+  client.Process(1)
+  flush_queued_messages()</pre>
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index 7604932..ca311ed 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -1,24 +1,663 @@
-page.title=GCM Client
-page.tags="cloud","push","messaging"
+page.title=Implementing GCM Client
+page.tags=cloud,push,messaging
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
+
+<h2>In this document</h2>
+
+<ol class="toc">
+<li><a href="#play-services">Set Up Google Play Services</a></li>
+<li><a href="#manifest">Edit Your Application's Manifest</a></li>
+<li><a href="#app">Write Your Application</a>
+  <ol class="toc">
+    <li><a href="#sample-play">Check for Google Play Services APK</a></li>
+    <li><a href="#sample-register">Register for GCM</a></li>
+    <li><a href="#sample-send">Send a message</a></li>
+    <li><a href="#sample-receive">Receive a message</a></li>
+  </ol>
+  <li><a href="#run">Running the Sample</a></li>
+  <li><a href="#stats">Viewing Statistics</a></li>
+</li>
+
+</ol>
+
 <h2>See Also</h2>
 
 <ol class="toc">
 <li><a href="gs.html">Getting Started</a></li>
-<li><a href="server.html">GCM Server</a></li>
+<li><a href="server.html">Implementing GCM Server</a></li>
 </ol>
 
 </div>
 </div>
 
-<p>A GCM client is a GCM-enabled app that runs on an Android device. To write your client code, we recommend that you use the new <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. The client helper library that was offered in previous versions of GCM still works, but it has been superseded by the more efficient <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs.</p>
+<p>A GCM client is a GCM-enabled app that runs on an Android device. To write your
+client code, we recommend that you use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs.
+The client helper library that was offered in previous versions of GCM still works,
+but it has been superseded by the more efficient
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs.</p>
 
-<p>A full GCM implementation requires both a client implementation and a server-side implementation. For a step-by-step guide to creating a complete sample implementation that includes both client and server, see <a href="gs.html">Getting Started</a>. </p>
+<p>A full GCM implementation requires both a client implementation and a server
+implementation. For more
+information about implementing the server side, see <a href="server.html">
+Implementing GCM Server</a>.</p>
 
-<p>
+<p>The following sections walk you through the steps involved in writing a GCM
+client-side application. Your client app can be arbitrarily complex, but at bare
+minimum, a GCM client app must include code to register (and thereby get a
+registration ID), and a broadcast receiver to receive messages sent by GCM.
+</p>
+
+<h2 id="play-services">Step 1: Set Up Google Play Services</h2>
+
+<p>To write your client application, use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> API.
+To use this API, you must set up your project to use the Google Play services SDK,
+as described in <a href="/google/play-services/setup.html">Setup Google Play
+Services SDK</a>.</p>
+
+<p class="note"><strong>Caution:</strong> When you add the Play Services library to
+your project, be sure to add it <em>with resources</em>, as described in
+<a href="{@docRoot}google/play-services/setup.html#Setup">
+Setup Google Play Services SDK</a>. The key point is that you must
+<em>reference</em> the library&mdash;simply adding a {@code .jar} file to
+your Eclipse project will not work. You must follow the directions
+for referencing a library, or your app won't be able to access
+the library's resources, and it won't run properly.
+If you're using Android Studio, this is the string to add to the
+{@code dependency} section of your application's {@code build.gradle} file:</p>
+
+<pre>dependencies {
+   compile: "com.google.android.gms:play-services:3.1.+"
+}
+</pre>
+
+
+<h2 id="manifest">Step 2: Edit Your Application's Manifest</h2>
+
+<p>Add the following to your application's manifest:</p>
+<ul>
+  <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so
+the Android application can register and receive messages.</li>
+  <li>The <code>android.permission.INTERNET</code> permission so the Android
+application can send the registration ID to the 3rd party server.</li>
+  <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires
+a Google account (necessary only if if the device is running a version lower than
+Android 4.0.4)</li>
+  <li>The <code>android.permission.WAKE_LOCK</code> permission so the application
+can keep the processor from sleeping when a message is received. Optional&mdash;use
+only if the app wants to keep the device from sleeping.</li>
+  <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code>
+permission to prevent other Android applications from registering and receiving
+the Android application's messages. The permission name must exactly match this
+pattern&mdash;otherwise the Android application will not receive the messages.</li>
+   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with
+the category set
+as <code>applicationPackage</code>. The receiver should require the
+<code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
+Framework can send a message to it. If your app uses an {@link android.app.IntentService}
+(not required, but a common pattern), this receiver should be an instance of
+{@link android.support.v4.content.WakefulBroadcastReceiver}.
+A {@link android.support.v4.content.WakefulBroadcastReceiver} takes care of
+creating and managing a
+<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
+partial wake lock</a> for your app.</li>
+
+<li>A {@link android.app.Service} (typically an {@link android.app.IntentService})
+to which the {@link android.support.v4.content.WakefulBroadcastReceiver} passes off
+the work of handling the GCM message, while ensuring that the device does not
+go back to sleep in the process. Including an {@link android.app.IntentService} is
+optional&mdash;you could choose to process your messages in a regular
+{@link android.content.BroadcastReceiver} instead, but realistically, most apps will
+use a {@link android.app.IntentService}.
+</li>
+  <li>If the GCM feature is critical to the Android application's function, be sure to
+set <code>android:minSdkVersion=&quot;8&quot;</code> or higher in the manifest. This
+ensures that the Android application cannot be installed in an environment in which it
+could not run properly. </li>
+</ul>
+
+<p>Here are excerpts from a sample manifest that supports GCM:</p>
+
+<pre class="prettyprint pretty-xml">
+&lt;manifest package="com.example.gcm" ...&gt;
+
+    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
+    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
+    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
+    &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
+    &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
+
+    &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE"
+        android:protectionLevel="signature" /&gt;
+    &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
+
+    &lt;application ...&gt;
+        &lt;receiver
+            android:name=".GcmBroadcastReceiver"
+            android:permission="com.google.android.c2dm.permission.SEND" &gt;
+            &lt;intent-filter&gt;
+                &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
+                &lt;category android:name="com.example.gcm" /&gt;
+            &lt;/intent-filter&gt;
+        &lt;/receiver&gt;
+        &lt;service android:name=".GcmIntentService" /&gt;
+    &lt;/application&gt;
+
+&lt;/manifest&gt;
+</pre>
+
+<h2 id="app"> Step 3: Write Your Application</h2>
+
+<p>Finally, write your application. This section features a sample client
+application that illustrates how to use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs. The sample consists of a main activity
+({@code DemoActivity}), a {@link android.support.v4.content.WakefulBroadcastReceiver}
+({@code GcmBroadcastReceiver}), and an {@link android.app.IntentService}
+({@code GcmIntentService}). You can find the complete source code for this sample at the
+<a href="http://code.google.com/p/gcm">open source site</a>.</p>
+
+<p>Note the following:</p>
+
+<ul>
+  <li>Among other things, the sample illustrates registration and upstream
+(device-to-cloud) messaging. Upstream messaging only applies to apps that are running against a
+<a href="ccs.html">CCS</a> (XMPP) server; HTTP-based servers don't support upstream messaging.</li>
+  <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+  {@code GoogleCloudMessaging}</a>
+registration APIs replace the old registration process, which was based on the
+now-obsolete client helper library. While the old registration process still works,
+we encourage you to use the newer
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+registration APIs, regardless of your underlying server.</li>
+</ul>
+
+<h3 id="sample-play">Check for Google Play Services APK</h3>
+
+<p>As described in <a href="{@docRoot}google/play-services/setup.html">
+Setup Google Play Services SDK</a>, apps that rely on the Play Services SDK
+should always check the device for a compatible Google Play services APK before
+accessing Google Play services features. In the sample app this check is done in
+two places: in the main activity's {@code onCreate()} method, and in its
+{@code onResume()} method. The check in {@code onCreate()} ensures that the app
+can't be used without a successful check. The check in {@code onResume()} ensures
+that if the user returns to the running app through some other means, such as
+through the back button, the check is still performed. If the
+device doesn't have a compatible Google Play services APK, your app can call
+{@code GooglePlayServicesUtil.getErrorDialog()} to allow users to download the
+APK from the Google Play Store or enable it in the device's system settings.
+For example:</p>
+
+<pre>private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
+...
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+
+    setContentView(R.layout.main);
+    mDisplay = (TextView) findViewById(R.id.display);
+
+    context = getApplicationContext();
+
+    // Check device for Play Services APK.
+    if (checkPlayServices()) {
+        // If this check succeeds, proceed with normal processing.
+        // Otherwise, prompt user to get valid Play Services APK.
+        ...
+    }
+}
+
+// You need to do the Play Services APK check here too.
+&#64;Override
+protected void onResume() {
+    super.onResume();
+    checkPlayServices();
+}
+
+/**
+ * Check the device to make sure it has the Google Play Services APK. If
+ * it doesn't, display a dialog that allows users to download the APK from
+ * the Google Play Store or enable it in the device's system settings.
+ */
+private boolean checkPlayServices() {
+    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
+    if (resultCode != ConnectionResult.SUCCESS) {
+        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
+            GooglePlayServicesUtil.getErrorDialog(resultCode, this,
+                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
+        } else {
+            Log.i(TAG, "This device is not supported.");
+            finish();
+        }
+        return false;
+    }
+    return true;
+}</pre>
+
+<h3 id="sample-register">Register for GCM</h3>
+<p>An Android application needs to register with GCM servers before it can receive
+messages. When an app registers, it receives a registration ID, which it can then
+store for future use. In the following snippet the {@code onCreate()} method in the sample app's
+main activity checks to see if the app is already registered with GCM and with
+the server:</p>
+
+<pre>/**
+ * Main UI for the demo app.
+ */
+public class DemoActivity extends Activity {
+
+    public static final String EXTRA_MESSAGE = "message";
+    public static final String PROPERTY_REG_ID = "registration_id";
+    private static final String PROPERTY_APP_VERSION = "appVersion";
+    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
+
+    /**
+     * Substitute you own sender ID here. This is the project number you got
+     * from the API Console, as described in "Getting Started."
+     */
+    String SENDER_ID = "Your-Sender-ID";
+
+    /**
+     * Tag used on log messages.
+     */
+    static final String TAG = "GCMDemo";
+
+    TextView mDisplay;
+    GoogleCloudMessaging gcm;
+    AtomicInteger msgId = new AtomicInteger();
+    SharedPreferences prefs;
+    Context context;
+
+    String regid;
+
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.main);
+        mDisplay = (TextView) findViewById(R.id.display);
+
+        context = getApplicationContext();
+
+        // Check device for Play Services APK. If check succeeds, proceed with
+        //  GCM registration.
+        if (checkPlayServices()) {
+            gcm = GoogleCloudMessaging.getInstance(this);
+            regid = getRegistrationId(context);
+
+            if (regid.isEmpty()) {
+                registerInBackground();
+            }
+        } else {
+            Log.i(TAG, "No valid Google Play Services APK found.");
+        }
+    }
+...
+}</pre>
+
+<p>The app calls {@code getRegistrationId()} to see whether there is an existing
+registration ID stored in shared preferences:</p>
+
+<pre>/**
+ * Gets the current registration ID for application on GCM service.
+ * &lt;p&gt;
+ * If result is empty, the app needs to register.
+ *
+ * &#64;return registration ID, or empty string if there is no existing
+ *         registration ID.
+ */
+private String getRegistrationId(Context context) {
+    final SharedPreferences prefs = getGCMPreferences(context);
+    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
+    if (registrationId.isEmpty()) {
+        Log.i(TAG, "Registration not found.");
+        return "";
+    }
+    // Check if app was updated; if so, it must clear the registration ID
+    // since the existing regID is not guaranteed to work with the new
+    // app version.
+    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
+    int currentVersion = getAppVersion(context);
+    if (registeredVersion != currentVersion) {
+        Log.i(TAG, "App version changed.");
+        return "";
+    }
+    return registrationId;
+}
+...
+/**
+ * &#64;return Application's {&#64;code SharedPreferences}.
+ */
+private SharedPreferences getGCMPreferences(Context context) {
+    // This sample app persists the registration ID in shared preferences, but
+    // how you store the regID in your app is up to you.
+    return getSharedPreferences(DemoActivity.class.getSimpleName(),
+            Context.MODE_PRIVATE);
+}</pre>
+
+<p>If the registration ID doesn't exist or the app was updated,
+{@code getRegistrationId()} returns an empty string
+to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls
+the following method to check the app version:</p>
+
+<pre>/**
+ * &#64;return Application's version code from the {&#64;code PackageManager}.
+ */
+private static int getAppVersion(Context context) {
+    try {
+        PackageInfo packageInfo = context.getPackageManager()
+                .getPackageInfo(context.getPackageName(), 0);
+        return packageInfo.versionCode;
+    } catch (NameNotFoundException e) {
+        // should never happen
+        throw new RuntimeException("Could not get package name: " + e);
+    }
+}</pre>
+
+
+<p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the
+following {@code registerInBackground()} method to register. Note that because the GCM
+methods {@code register()} and {@code unregister()} are blocking, this has to
+take place on a background thread. This sample uses {@link android.os.AsyncTask}
+to accomplish this:</p>
+
+<pre>
+/**
+ * Registers the application with GCM servers asynchronously.
+ * &lt;p&gt;
+ * Stores the registration ID and app versionCode in the application's
+ * shared preferences.
+ */
+private void registerInBackground() {
+    new AsyncTask<Void, Void, String>() {
+        &#64;Override
+        protected String doInBackground(Void... params) {
+            String msg = "";
+            try {
+                if (gcm == null) {
+                    gcm = GoogleCloudMessaging.getInstance(context);
+                }
+                regid = gcm.register(SENDER_ID);
+                msg = "Device registered, registration ID=" + regid;
+
+                // You should send the registration ID to your server over HTTP,
+                // so it can use GCM/HTTP or CCS to send messages to your app.
+                // The request to your server should be authenticated if your app
+                // is using accounts.
+                sendRegistrationIdToBackend();
+
+                // For this demo: we don't need to send it because the device
+                // will send upstream messages to a server that echo back the
+                // message using the 'from' address in the message.
+
+                // Persist the regID - no need to register again.
+                storeRegistrationId(context, regid);
+            } catch (IOException ex) {
+                msg = "Error :" + ex.getMessage();
+                // If there is an error, don't just keep trying to register.
+                // Require the user to click a button again, or perform
+                // exponential back-off.
+            }
+            return msg;
+        }
+
+        &#64;Override
+        protected void onPostExecute(String msg) {
+            mDisplay.append(msg + "\n");
+        }
+    }.execute(null, null, null);
+    ...
+    /**
+     * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
+     * or CCS to send messages to your app. Not needed for this demo since the
+     * device sends upstream messages to a server that echoes back the message
+     * using the 'from' address in the message.
+     */
+    private void sendRegistrationIdToBackend() {
+      // Your implementation here.
+    }
+}</pre>
+
+<p>After registering, the app calls {@code storeRegistrationId()} to store the
+registration ID in shared preferences for future use. This is just one way of
+persisting a regID. You might choose to use a different approach in your app:</p>
+
+<pre>/**
+ * Stores the registration ID and app versionCode in the application's
+ * {&#64;code SharedPreferences}.
+ *
+ * &#64;param context application's context.
+ * &#64;param regId registration ID
+ */
+private void storeRegistrationId(Context context, String regId) {
+    final SharedPreferences prefs = getGCMPreferences(context);
+    int appVersion = getAppVersion(context);
+    Log.i(TAG, "Saving regId on app version " + appVersion);
+    SharedPreferences.Editor editor = prefs.edit();
+    editor.putString(PROPERTY_REG_ID, regId);
+    editor.putInt(PROPERTY_APP_VERSION, appVersion);
+    editor.commit();
+}</pre>
+
+<h3 id="sample-send">Send a message</h3>
+<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
+upstream message using the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs. In order to receive the upstream message,
+your server should be connected to CCS. You can use one of the demo servers in
+<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
+to CCS.</p>
+
+<pre>public void onClick(final View view) {
+    if (view == findViewById(R.id.send)) {
+        new AsyncTask<Void, Void, String>() {
+            &#64;Override
+            protected String doInBackground(Void... params) {
+                String msg = "";
+                try {
+                    Bundle data = new Bundle();
+                        data.putString("my_message", "Hello World");
+                        data.putString("my_action",
+                                "com.google.android.gcm.demo.app.ECHO_NOW");
+                        String id = Integer.toString(msgId.incrementAndGet());
+                        gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
+                        msg = "Sent message";
+                } catch (IOException ex) {
+                    msg = "Error :" + ex.getMessage();
+                }
+                return msg;
+            }
+
+            &#64;Override
+            protected void onPostExecute(String msg) {
+                mDisplay.append(msg + "\n");
+            }
+        }.execute(null, null, null);
+    } else if (view == findViewById(R.id.clear)) {
+        mDisplay.setText("");
+    }
+}</pre>
+
+<h3 id="sample-receive">Receive a message</h3>
+
+<p>As described above in <a href="#manifest">Step 2</a>, the app includes a
+{@link android.support.v4.content.WakefulBroadcastReceiver} for the <code>com.google.android.c2dm.intent.RECEIVE</code>
+intent. A broadcast receiver is the mechanism GCM uses to deliver messages. When {@code onClick()}
+calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()}
+method, which has the responsibility of making sure that the GCM message gets handled.</p>
+<p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
+broadcast receiver that takes care of
+creating and managing a
+<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
+partial wake lock</a> for your app.
+It passes off the work of processing the GCM message to a
+{@link android.app.Service} (typically an
+{@link android.app.IntentService}), while ensuring that the device does not
+go back to sleep in the transition. If you don't hold a wake lock while transitioning
+the work to a service, you are effectively allowing the device to go back to sleep before
+the work completes. The net result is that the app might not finish processing
+the GCM message until some arbitrary point in the future, which is not what you want.</p>
+
+<p class="note"><strong>Note:</strong> Using {@link android.support.v4.content.WakefulBroadcastReceiver}
+is not a requirement. If you have a relatively simple app that doesn't require
+a service, you can intercept the GCM message in a regular {@link android.content.BroadcastReceiver}
+and do your processing there. Once you get the intent that GCM passes into
+your broadcast receiver's {@code onReceive()} method, what you do with it
+is up to you.</p>
+
+<p>This snippet starts {@code GcmIntentService} with the method
+{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}.
+This method is comparable to {@link android.content.Context#startService startService()}, except that
+the {@link android.support.v4.content.WakefulBroadcastReceiver} is holding a
+wake lock when the service starts. The intent that is passed with
+{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}
+holds an extra identifying the wake lock:</p>
+
+
+<pre>public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
+    &#64;Override
+    public void onReceive(Context context, Intent intent) {
+        // Explicitly specify that GcmIntentService will handle the intent.
+        ComponentName comp = new ComponentName(context.getPackageName(),
+                GcmIntentService.class.getName());
+        // Start the service, keeping the device awake while it is launching.
+        startWakefulService(context, (intent.setComponent(comp)));
+        setResultCode(Activity.RESULT_OK);
+    }
+}</pre>
+
+<p>The intent service shown below does the actual work of handling the GCM
+message. When the service is finished, it calls
+{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent GcmBroadcastReceiver.completeWakefulIntent()}
+to release the wake lock. The
+{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent completeWakefulIntent()}
+method has as its parameter the same intent that was
+passed in from the {@link android.support.v4.content.WakefulBroadcastReceiver}.
+</p>
+
+<p>This snippet processes the GCM message based on message type, and posts the
+result in a notification. But what you do with GCM messages in your app is up to
+you&mdash;the possibilities are endless. For example, the message might be a ping,
+telling the app to sync to a server to retrieve new content, or it might be a
+chat message that you display in the UI.</p>
+
+<pre>
+public class GcmIntentService extends IntentService {
+    public static final int NOTIFICATION_ID = 1;
+    private NotificationManager mNotificationManager;
+    NotificationCompat.Builder builder;
+
+    public GcmIntentService() {
+        super("GcmIntentService");
+    }
+
+    &#64;Override
+    protected void onHandleIntent(Intent intent) {
+        Bundle extras = intent.getExtras();
+        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
+        // The getMessageType() intent parameter must be the intent you received
+        // in your BroadcastReceiver.
+        String messageType = gcm.getMessageType(intent);
+
+        if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
+            /*
+             * Filter messages based on message type. Since it is likely that GCM
+             * will be extended in the future with new message types, just ignore
+             * any message types you're not interested in, or that you don't
+             * recognize.
+             */
+            if (GoogleCloudMessaging.
+                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
+                sendNotification("Send error: " + extras.toString());
+            } else if (GoogleCloudMessaging.
+                    MESSAGE_TYPE_DELETED.equals(messageType)) {
+                sendNotification("Deleted messages on server: " +
+                        extras.toString());
+            // If it's a regular GCM message, do some work.
+            } else if (GoogleCloudMessaging.
+                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {
+                // This loop represents the service doing some work.
+                for (int i=0; i<5; i++) {
+                    Log.i(TAG, "Working... " + (i+1)
+                            + "/5 @ " + SystemClock.elapsedRealtime());
+                    try {
+                        Thread.sleep(5000);
+                    } catch (InterruptedException e) {
+                    }
+                }
+                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
+                // Post notification of received message.
+                sendNotification("Received: " + extras.toString());
+                Log.i(TAG, "Received: " + extras.toString());
+            }
+        }
+        // Release the wake lock provided by the WakefulBroadcastReceiver.
+        GcmBroadcastReceiver.completeWakefulIntent(intent);
+    }
+
+    // Put the message into a notification and post it.
+    // This is just one simple example of what you might choose to do with
+    // a GCM message.
+    private void sendNotification(String msg) {
+        mNotificationManager = (NotificationManager)
+                this.getSystemService(Context.NOTIFICATION_SERVICE);
+
+        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+                new Intent(this, DemoActivity.class), 0);
+
+        NotificationCompat.Builder mBuilder =
+                new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_stat_gcm)
+        .setContentTitle("GCM Notification")
+        .setStyle(new NotificationCompat.BigTextStyle()
+        .bigText(msg))
+        .setContentText(msg);
+
+        mBuilder.setContentIntent(contentIntent);
+        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
+    }
+}</pre>
+
+<h2 id="run">Running the Sample</h2>
+
+<p>To run the sample:</p>
+
+<ol>
+  <li>Follow the instructions in <a href="gs.html">Getting Started</a> to get your sender ID and
+  API key.</li>
+  <li>Implement your client app, as described in this document. You can find the complete source
+  code for the client app at the <a href="http://code.google.com/p/gcm">open source site</a>.</li>
+  <li>Run one of the demo servers (Java or Python) provided in
+<a href="ccs.html#implement">Implementing an XMPP-based App Server</a>. Whichever demo server you
+ choose, don't forget to edit its code before running it to supply
+your sender ID and API key.
+</li>
+
+</ol>
+
+<h2 id="stats">Viewing Statistics</h2>
+
+<p>To view  statistics and any error messages for your GCM applications:</p>
+<ol>
+  <li> Go to the <code><a href="http://play.google.com/apps/publish">Developer Console</a></code>.</li>
+  <li>Login with your developer account.
+  <p>You will see a page that has a list of all of your apps.</p></li>
+  <li> Click on the &quot;statistics&quot; link next to the app for which you
+want to view GCM stats.
+  <p>Now you are on the statistics page.</p> </li>
+  <li>Go to the drop-down menu and select the GCM metric you want to view.
+  </li>
+</ol>
+<p class="note"><strong>Note:</strong> Stats on the Google API Console are not
+enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>
 
 
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index ceb82b0..3c80b5f 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -1,48 +1,23 @@
-page.title=GCM Architectural Overview
+page.title=Overview
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Quickview</h2>
-
-<ul>
-<li>Get an introduction to key GCM terms and concepts.</li>
-<li>Learn the basic features of a GCM application.</li>
-<li>Understand the role of the 3rd-party application server, and how to send messages and process results.</li>
-</ul>
-
-
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#intro">Introduction</a> </li>
-  <li><a href="#arch">Architectural Overview</a>
-    <ol>
-      <li><a href="#lifecycle">Lifecycle Flow</a></li>
-        <ol>
-          <li><a href="#register">Enable GCM</a></li>
-          <li><a href="#push-process">Send a message</a></li>
-          <li><a href="#receiving">Receive a message</a></li>
-        </ol>
-      <li><a href="#user">What Does the User See?</a></li>
-    </ol>
-  </li>
-  <li><a href="#server">Role of  the 3rd-party Application Server</a>
+  <li><a href="#key">Key Concepts</a></li>
+  <li><a href="#arch">Architectural Overview</a></li>
+  <li><a href="#lifecycle">Lifecycle Flow</a>
     <ol class="toc">
-      <li><a href="#send-msg">Sending Messages</a>
-        <ol>
-          <li><a href="#request">Request format</a></li>
-          <li><a href="#response">Response format</a></li>
-        </ol>
-      </li>
+      <li><a href="#register">Enable GCM</a></li>
+      <li><a href="#push-process">Send a message</a></li>
+      <li><a href="#receiving">Receive a message</a></li>
     </ol>
-    <li><a href="#stats">Viewing Statistics</a>
   </li>
 </ol>
 
-
-
 </div>
 </div>
 
@@ -50,24 +25,15 @@
 developers  send data from servers to their Android applications on  Android
 devices, and upstream messages from the user's device back to the cloud.
 This could be a lightweight message telling the Android application
-that there is new data to be fetched from the server (for instance, a movie
-uploaded by a friend), or it could be a message containing up to 4kb of payload
+that there is new data to be fetched from the server (for instance, a "new email"
+notification informing the application that it is out of sync with the back end),
+or it could be a message containing up to 4kb of payload
 data (so apps like instant messaging can consume the message directly). The GCM
 service handles all aspects  of queueing of messages and delivery to the target
 Android application running  on the target device.</p>
-
-<p>GCM introduces GCM Cloud Connection Server (CCS), which you can use
-in tandem with GCM HTTP service/endpoint/APIs.
-CCS uses XMPP, and it offers asynchronous, bidirectional
-messaging. For more information, see
-<a href="ccs.html">GCM Cloud Connection Server</a>.
-  
   
 <p class="note"> To jump right into using GCM with your Android
-  applications, see the instructions in <a href="gs.html">Getting Started</a>.</p>
-
-
-<h2 id="intro">Introduction</h2>
+  applications, see <a href="gs.html">Getting Started</a>.</p>
 
 <p>Here are the primary characteristics of Google Cloud 
 Messaging (GCM):</p>
@@ -75,9 +41,11 @@
 <ul>
   <li>It allows 3rd-party application servers to send messages to
 their Android applications.</li>
-  <li>Using the <a href="ccs.html">GCM Cloud Connection Server</a>, you can receive upstream messages from the user's device.</li>
+  <li>Using the <a href="ccs.html">GCM Cloud Connection Server</a>, you can receive
+upstream messages from the user's device.</li>
   <li>An Android application on an Android device doesn't need to be running to receive
-messages. The system will wake up the Android application via Intent broadcast when the  message arrives, as long as the application is set up with the proper
+messages. The system will wake up the Android application via Intent broadcast
+when the  message arrives, as long as the application is set up with the proper
 broadcast receiver and permissions.</li>
   <li>It does not provide any  built-in user interface or other handling for
 message data. GCM  simply passes raw message data received straight to the
@@ -85,57 +53,67 @@
 application might post a notification, display a custom user interface, or 
 silently sync data.</li>
   <li>It requires devices running Android 2.2 or higher that also have the
-Google Play Store application installed, or or an emulator running Android 2.2 with Google APIs. However, you are not limited to deploying your
+Google Play Store application installed, or or an emulator running Android 2.2
+with Google APIs. However, you are not limited to deploying your
 Android applications through Google Play Store.</li>
-  <li>It uses an existing connection for Google services. For pre-3.0 devices, this requires users to
-set up their Google account on their mobile devices. A Google account is not a requirement on devices running Android 4.0.4 or higher.</li>
+  <li>It uses an existing connection for Google services. For pre-3.0 devices,
+this requires users to
+set up their Google account on their mobile devices. A Google account is not a
+requirement on devices running Android 4.0.4 or higher.</li>
 </ul>
-<h2 id="arch">Architectural Overview</h2>
-<p>This section gives an overview of how GCM works. </p>
+
+<h2 id="key">Key Concepts</h2>
+
 <p>This table summarizes the key terms and concepts involved in GCM. It is
 divided into these categories:</p>
 <ul>
-  <li><strong>Components</strong> &mdash; The physical entities that play a role in
+  <li><strong>Components</strong> &mdash; The entities that play a primary role in
 GCM.</li>
   <li><strong>Credentials</strong> &mdash; The IDs and tokens that are used in
 different stages of GCM to ensure that all parties have been authenticated, and
 that the message is going to the correct place.</li>
 </ul>
 
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> GCM components and credentials.</p>
+
 <table>
   <tr>
     <th colspan="2">Components</th>
   </tr>
   <tr>
-    <td width="165"><strong>Mobile Device</strong></td>
-    <td width="1176">The device that is running an Android application that uses
-GCM. This must be a 2.2 Android device that has Google Play Store installed, and it must
-have at least one logged in Google account if the device is running a version lower than Android 4.0.4. Alternatively, for testing you can use an emulator running Android 2.2 with Google APIs.</td>
+    <td width="165"><strong>Client App</strong></td>
+    <td width="1176">The GCM-enabled Android application that is running on a
+    device. This must be a 2.2 Android device that has Google Play Store installed, and it must
+have at least one logged in Google account if the device is running a version
+lower than Android 4.0.4. Alternatively, for testing you can use an emulator
+running Android 2.2 with Google APIs.</td>
   </tr>
   <tr>
     <td><strong>3rd-party Application Server</strong></td>
-    <td>An application server that  developers  set up as part of implementing
-GCM in their applications. The 3rd-party application server sends data to an
-Android application on the device via the GCM server.</td>
+    <td>An application server that you write as part of implementing
+GCM. The 3rd-party application server sends data to an
+Android application on the device via the GCM connection server.</td>
   </tr>
   <tr>
-    <td><strong>GCM Servers</strong></td>
-    <td>The Google servers involved in taking messages from the 3rd-party
+    <td><strong>GCM Connection Servers</strong></td>
+    <td>The Google-provided servers involved in taking messages from the 3rd-party
 application server and sending them to the device. </td>
   </tr>
   <tr>
-    <th colspan="2"><strong>Credentials</strong></th>
+    <th colspan="2">Credentials</th>
   </tr>
   <tr>
     <td><strong>Sender ID</strong></td>
-    <td>A project number you acquire from the API console, as described in <a href="gs.html#create-proj">Getting Started</a>. The sender
-ID is used in the <a href="#registering">registration process</a> to identify an
-Android application that is permitted to send messages to the device.</td>
+    <td>A project number you acquire from the API console, as described in
+<a href="gs.html#create-proj">Getting Started</a>. The sender
+ID is used in the <a href="#register">registration process</a> to identify a
+3rd-party application server that is permitted to send messages to the device.</td>
   </tr>
   <tr>
     <td><strong>Application ID</strong></td>
     <td>The Android application that is registering to receive messages. The Android application
-is identified by the package name from the <a href="#manifest">manifest</a>.
+is identified by the package name from the <a href="client.html#manifest">manifest</a>.
 This  ensures that the messages are targeted to the correct Android application.</td>
   </tr>
   <tr>
@@ -158,7 +136,8 @@
   </tr>
   <tr>
     <td><strong>Google User Account</strong></td>
-    <td>For GCM to work, the mobile device must include at least one Google account if the device is running a version lower than Android 4.0.4.</td>
+    <td>For GCM to work, the mobile device must include at least one Google
+account if the device is running a version lower than Android 4.0.4.</td>
   </tr>
   <tr>
     <td><strong>Sender Auth Token</strong></td>
@@ -167,25 +146,46 @@
 The API key is included in the header of POST requests  that send messages.</td>
   </tr>
 
-  <tr>
-    <td><strong>Notification Key</strong></td>
-    <td>Part of the user notifications feature, which provides a mapping between a user and instances of an app running on multiple devices owned by the user. The {@code notification_key} is the token that GCM uses to fan out notifications to all devices whose registration IDs are associated with the key. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</td>
-  </tr>
-
-<tr>
-    <td><strong>Notification Key Name</strong></td>
-    <td>Part of the user notifications feature. The {@code notification_key_name} is a name or identifier (can be a username for a 3rd-party app) that is unique to a given user. It is used by third parties to group together registration IDs for a single user. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</td>
-  </tr>
-
 </table>
 
-<h3 id="lifecycle">Lifecycle Flow</h3>
+<h2 id="arch">Architectural Overview</h2>
+
+<p>A GCM implementation includes a Google-provided
+connection server, a 3rd-party app server that interacts with the connection
+server, and a GCM-enabled client app running on an Android device:</p>
+
+<img src="{@docRoot}images/gcm/GCM-arch.png">
+
+<p class="img-caption">
+  <strong>Figure 1.</strong> GCM Architecture.
+</p>
+
+<p>This is how these components interact:</p>
+<ul>
+  <li>Google-provided <strong>GCM Connection Servers</strong> take messages from
+a 3rd-party application server and send these messages to a
+GCM-enabled Android application (the &quot;client app&quot;) running on a device.
+Currently Google provides connection servers for <a href="http.html">HTTP</a>
+and <a href="ccs.html">XMPP</a>.</li>
+  <li>The <strong>3rd-Party Application Server</strong> is a component that you
+implement to work with your chosen GCM connection server(s). App servers send
+messages to a GCM connection server; the connection server enqueues and stores the
+message, and then sends it to the device when the device is online.
+For more information, see <a href="server.html">Implementing GCM Server</a>.</li>
+  <li>The <strong>Client App</strong> is a GCM-enabled Android application running
+on a device. To receive GCM messages, this app must register with GCM and get a
+registration ID. If you are using the <a href="ccs.html">XMPP</a> (CCS) connection
+server, the client app can send "upstream" messages back to the connection server.
+For more information on how to implement the client app, see
+<a href="client.html">Implementing GCM Client</a>.</li>
+</ul>
+
+<h2 id="lifecycle">Lifecycle Flow</h2>
 
 <ul>
   <li><a href="#register">Enable GCM</a>. An Android application running on a
 mobile device registers to receive messages.</li>
- <li><a href="notifications.html">User Notifications</a>. A 3rd-party server can optionally group multiple registration IDs
-in a {@code notification_key} to send messages to multiple devices owned by a single user.</li>
+
   <li><a href="#push-process">Send a message</a>. A 3rd-party application
 server sends messages to the device.</li>
   <li><a href="#receiving">Receive a message</a>. An Android application
@@ -194,62 +194,18 @@
 
 <p>These processes are described in more detail below.</p>
 
-<h4 id="register">Enable GCM</h4>
+<h3 id="register">Enable GCM</h3>
 
-<p>This is the sequence of events that occurs when an Android application
-running on a mobile device registers to receive messages:<span
-class="red-text"></span></p>
-
-<ol>
-  <li>The first time the Android application needs to use the messaging service, it
-fires off a registration Intent to a GCM server.
-    <p>This registration Intent
-(<code>com.google.android.c2dm.intent.REGISTER</code>) includes the sender ID, and the Android application ID.</p>
-<p class="note"><strong>Note:</strong> Because there is no lifecycle method that is called when the application is run for
-the first time, the registration intent should be sent on <code>onCreate()</code>, but only if the application is not registered yet.
+<p>The first time the Android application needs to use the messaging service, it
+calls the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> method {@code register()}, as discussed in
+<a href="client.html">Implementing GCM Client</a>.
+The {@code register()} method returns a registration ID. The Android
+application should store this ID for later use (for instance,
+to check in <code>onCreate()</code> if it is already registered).
 </p>
-  </li>
-  <li>If the registration is successful, the GCM server broadcasts a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent which gives the Android application  a registration
-ID. 
-    <p>The Android application should store this ID for later use (for instance, to check on <code>onCreate()</code> if it is already registered).
-Note that Google may periodically refresh the registration ID, so you should design your Android application
-with the understanding that the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent may be called
-multiple times. Your Android application needs to be able to respond
-accordingly.</p></li>
-  <li>To complete the registration, the Android application sends the registration ID to
-the application server. The application server typically stores the registration
-ID in a database. </li>
-</ol>
 
-<p>The registration ID lasts until the Android application explicitly unregisters
-itself, or until Google refreshes the registration ID for your Android application.</p>
-
-<p class="note"><strong>Note:</strong> When users uninstall an application, it is not automatically unregistered on GCM. It is only  unregistered when the GCM server tries to send a message to the device and the device answers that the application is uninstalled or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents. At that point, your server should mark the device as unregistered (the server will receive a <code><a href="#unreg_device">NotRegistered</a></code> error).</p>
-  <p>
-Note that it might take a few minutes for the registration ID to be completely removed from the GCM server. So if the 3rd-party server sends a message during this time, it will get a valid message ID, even though the message will not be delivered to the device.</p>
-
-
-
-
-<h4 id="push-process">Send a Message</h4>
-
-<p>For an application server to send a  message to an Android application, the following things must be in
-place:</p>
-
-<ul>
-  <li>The Android application has stored a target that it can specify as the recipient of a message. This can be one of the following:
-  <ul>
-    <li>A single registration ID (or an array of registration IDs) that allows the app to receive messages
-for a particular device.</li>
-    <li>A {@code notification_key} and corresponding {@code notification_key_name}, used to map a single user to multiple registration IDs. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</li>
-  </ul>
-    </li>
-
-<li>An API key. This is something that the developer must have already
-set up on the application server for the Android application (for more discussion, see
-<a href="#server">Role of the 3rd-party Application Server</a>). Now it will
-get used to send messages to the device. </li>
-</ul>
+<h3 id="push-process">Send a message</h3>
 
 <p>Here is the sequence of events that occurs when the application server sends a 
 message:</p>
@@ -264,13 +220,14 @@
 targeted Android application gets the message. This wakes the Android application up. The
 Android application does not need to be running beforehand to receive the message.</li>
   <li>The Android application processes the message. If the Android application is doing
-non-trivial processing, you may want to grab a {@link android.os.PowerManager.WakeLock} and do any processing in a Service.</li>
+non-trivial processing, you may want to grab a
+{@link android.os.PowerManager.WakeLock} and do any processing in a service.</li>
 </ol>
 
 <p> An Android application can  unregister GCM if it no longer wants to receive 
 messages.</p>
 
-<h4 id="receiving">Receive a Message</h4>
+<h3 id="receiving">Receive a message</h3>
 
 <p>This is the sequence of events that occurs when an Android application
 installed on a mobile device receives a message:</p>
@@ -282,482 +239,8 @@
 in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
 extras.</li>
   <li>The Android application extracts the raw data
-from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent by key and processes the data.</li>
+from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
+by key and processes the data.</li>
 </ol>
 
-<h3 id="user">What Does the User See?</h3>
-
-<p>When mobile device users install Android applications that include GCM, the Google Play Store will inform them that the Android application
-includes GCM. They must approve the use of this feature to install the
-Android application. </p>
-
-
-<h2 id="server">Role of the 3rd-party Application Server</h2>
-
-<p>Before you can write client Android applications that use the GCM feature, you must
-have an  application server that meets the following criteria:</p>
-
-<ul>
-  <li>Able to communicate with your client.</li>
-  <li>Able to  fire off HTTPS requests to the GCM server.</li>
-  <li>Able to handle requests and resend them as needed, using <a href="http://en.wikipedia.org/wiki/Exponential_backoff">exponential back-off.</a></li>
-  <li>Able to store the API key and client registration IDs. The
-API key is included in the header of POST requests that send
-messages.</li>
-</ul>
-
-<h3 id="send-msg">Sending Messages</h3>
-<p>This section describes how the 3rd-party application server sends messages to one or more mobile devices. Note the following:</p>
-<ul>
-  <li>A 3rd-party application server can either send messages to a single device or to multiple devices. A message sent to multiple devices simultaneously is called a <em>multicast message</em>.</li>
-  <li>To send a single message to multiple devices owned by a single user, you can use a {@code notification_key}, as described in <a href="notifications.html">User Notifications</a>.
-  
-  <li>You have 2 choices in how you construct requests and responses: plain text or JSON.</li>
-  <li>However, to send multicast messages, you must use JSON. Plain text will not work.</li>
-</ul>
-<p>Before the 3rd-party application server can send a  message to an
-  Android application, it must have received a registration ID from it.</p>
-<h4 id="request">Request format</h4>
-<p>To send a  message, the application server issues a POST request to <code>https://android.googleapis.com/gcm/send</code>.</p>
-<p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
-
-<p>The HTTP header must contain the following headers:</p>
-<ul>
-  <li><code>Authorization</code>: key=YOUR_API_KEY</li>
-  <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
-  </li>
-</ul>
-
-<p>For example:
-</p>
-<pre>Content-Type:application/json
-Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
-
-{
-  "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
-  "data" : {
-    ...
-  },
-}</pre>
-<p class="note">
-  <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format is assumed to be plain text.</p>
-</p>
-
-<p>The HTTP body content depends on whether you're using JSON or plain text. For JSON, it must contain a string representing a JSON object with the following fields:</p>
-<table>
-  <tr>
-    <th>Field</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>registration_ids</code></td>
-    <td>A string array with the list of devices (registration IDs) receiving the message. It must contain at least 1 and at most 1000 registration IDs. To send a multicast message, you must use JSON. For sending a single message to a single device, you could use a JSON object with just 1 registration id, or plain text (see below). A request must include a recipient&mdash;this can be either a registration ID, an array of registration IDs, or a {@code notification_key}.</td>
-  </tr>
- <tr>
-    <td><code>notification_key</code></td>
-    <td>A string that maps a single user to multiple registration IDs associated with that user. This
-allows a 3rd-party server to send a single message to multiple app instances (typically on multiple devices) owned by a single user. A 3rd-party server can use {@code notification_key} as the target for a message instead of an individual registration ID (or array of registration IDs). The maximum number of members allowed for a {@code notification_key} is 10. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>. Optional.</td>
-  </tr>
-
-<tr>
-    <td><code>notification_key_name</code></td>
-    <td>A name or identifier (can be a username for a 3rd-party app) that is unique to a given user. It is used by 3rd parties to group together registration IDs for a single user. The <code>notification_key_name</code> should be uniquely named per app in case you have multiple apps for the same project ID. This ensures that notifications only go to the intended target app. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</td>
-  </tr>
-
-  <tr>
-    <td><code>collapse_key</code></td>
-    <td>An arbitrary string (such as &quot;Updates Available&quot;) that is used to collapse a group of like messages
-when the device is offline, so that only the last message gets sent to the
-client. This is intended to avoid sending too many messages to the phone when it
-comes back online. Note that since there is no guarantee of the order in which
-messages get sent, the &quot;last&quot; message may not actually be the last
-message sent by the application server. See <a href="adv.html#collapsible">Advanced Topics</a> for more discussion of this topic. Optional.</td>
-  </tr>
-  <tr>
-    <td><code>data</code></td>
-    <td>A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it will be
-included in the Intent as application data, with the key being the extra's name. For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. 
-
-There is no limit on the number of key/value pairs, though there is a limit on the total size of the message (4kb). The values could be any JSON object, but we recommend using strings, since the values will be converted to strings in the GCM server anyway. If you want to include objects or other non-string data types (such as integers or booleans), you have to do the conversion to string yourself. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with <code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
-
-
-  </tr>
-  <tr>
-    <td><code>delay_while_idle</code></td>
-    <td>If included, indicates that the message should not be sent immediately
-if the device is idle. The server will wait for the device to become active, and
-then only the last message for each <code>collapse_key</code> value will be
-sent. Optional. The default value is <code>false</code>, and must be a JSON boolean.</td>
-  </tr>
-  <tr>
-    <td><code>time_to_live</code></td>
-    <td>How long (in seconds) the message should be kept on GCM storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as a JSON number).</td>
-  </tr>
-<tr>
-  <td><code>restricted_package_name</code></td>
-  <td>A string containing the package name of your application. When set, messages will only be sent to registration IDs that match the package name. Optional.
-  </td>
-</tr>
-<tr>
-  <td><code>dry_run</code></td>
-  <td>If included, allows developers to test their request without actually sending a message. Optional. The default value is <code>false</code>, and must be a JSON boolean.
-  </td>
-</tr>
-</table>
-
-<p>If you are using plain text instead of JSON, the message fields must be set as HTTP parameters sent in the body, and their syntax is slightly different, as described below:
-<table>
-  <tr>
-    <th>Field</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>registration_id</code></td>
-    <td>Must contain the registration ID of the single device receiving the message. Required.</td>
-  </tr>
-  <tr>
-    <td><code>collapse_key</code></td>
-    <td>Same as JSON (see previous table). Optional.</td>
-  </tr>
-  <tr>
-    <td><code>data.&lt;key&gt;</code></td>
-
-    <td>Payload data, expressed as parameters prefixed with <code>data.</code> and suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. There is no limit on the number of key/value parameters, though there is a limit on the total size of the  message. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with 
-<code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
-
-  </tr>
-  <tr>
-    <td><code>delay_while_idle</code></td>
-    <td>Should be represented as <code>1</code> or <code>true</code> for <code>true</code>, anything else for <code>false</code>. Optional. The default value is <code>false</code>.</td>
-  </tr>
-  <tr>
-    <td><code>time_to_live</code></td>
-    <td>Same as JSON (see previous table). Optional.</td>
-  </tr>
-<tr>
-  <td><code>restricted_package_name</code></td>
-  <td>Same as JSON (see previous table). Optional.
-  </td>
-</tr>
-<tr>
-  <td><code>dry_run</code></td>
-  <td>Same as JSON (see previous table). Optional.
-  </td>
-</tr>
-</table>
-
-<p>If you want to test your request (either JSON or plain text) without delivering the message to the devices, you can set an optional HTTP or JSON parameter called <code>dry_run</code> with the value <code>true</code>. The result will be almost identical to running the request without this parameter, except that the message will not be delivered to the devices. Consequently, the response will contain fake IDs for the message and multicast fields (see <a href="#response">Response format</a>).</p>
-
-  <h4 id="example-requests">Example requests</h4>
-  <p>Here is the smallest possible request (a message without any parameters and just one recipient) using JSON:</p>
-  <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
-  
-  <p>And here the same example using plain text:</p>
-  <pre class="prettyprint">registration_id=42</pre>
-  
-  <p> Here is a message with a payload and 6 recipients:</p>
-  <pre class="prettyprint pretty-HTML">{ "data": {
-    "score": "5x1",
-    "time": "15:10"
-  },
-  "registration_ids": ["4", "8", "15", "16", "23", "42"]
-}</pre>
-  <p>Here is a message with all optional fields set and 6 recipients:</p>
-  <pre class="prettyprint pretty-json">{ "collapse_key": "score_update",
-  "time_to_live": 108,
-  "delay_while_idle": true,
-  "data": {
-    "score": "4x8",
-    "time": "15:16.2342"
-  },
-  "registration_ids":["4", "8", "15", "16", "23", "42"]
-}</pre>
-  <p>And here is the same message using plain-text format (but just 1 recipient):  </p>
-  
-  <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
-  </pre>
-
-<p class="note"><strong>Note:</strong> If your organization has a firewall 
-that restricts the traffic to or 
-from the Internet, you need to configure it to allow connectivity with GCM in order for
-your Android devices to receive messages. 
-The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
-it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
-your firewall to accept outgoing connections to all IP addresses
-contained in the IP blocks listed in Google's ASN of 15169.</p>
-
-
-<h4 id="response">Response format</h4>
-
-<p>There are two possible outcomes when trying to send a message:</p>
-<ul>
-  <li>The message is processed successfully.</li>
-  <li>The GCM server rejects the request.</li>
-</ul>
-
-<p>When the message is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected, 
-the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
-
-<p>The following table summarizes the statuses that the HTTP response header might contain. Click the troubleshoot link for advice on how to deal with each type of error.</p>
-<table border=1>
-  <tr>
-    <th>Response</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td>200</td>
-    <td>Message was processed successfully. The response body will contain more details about the message status, but its format will depend whether the request was JSON or plain text. See <a href="#success">Interpreting a success response</a> for more details.</td>
-  </tr>
-  <tr>
-    <td>400</td>
-    <td><span id="internal-source-marker_0.2">Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields (for instance, passing a string where a number was expected). The exact failure reason is described in the response and the problem should be addressed before the request can be retried.</td>
-  </tr>
-  <tr>
-    <td>401</td>
-    <td>There was an error authenticating the sender account. <a href="#auth_error">Troubleshoot</a></td>
-  </tr>
-  <tr>
-    <td>5xx</td>
-    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there was an internal error in the GCM server while trying to process the request, or that the server is temporarily unavailable (for example, because of timeouts). Sender must retry later, honoring any <code>Retry-After</code> header included in the response. Application servers must implement exponential back-off. <a href="#internal_error">Troubleshoot</a></td>
-  </tr>
-</table>
-
-<h4 id="success">Interpreting a success response</h4>
-<p>When a JSON request is successful (HTTP status code 200), the response body contains a JSON object with the following fields:</p>
-<table>
-  <tr>
-    <th>Field</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>multicast_id</code></td>
-    <td>Unique ID (number) identifying the multicast message.</td>
-  </tr>
-  <tr>
-    <td><code>success</code></td>
-    <td>Number of messages that were processed without an error.</td>
-  </tr>
-  <tr>
-    <td><code>failure</code></td>
-    <td>Number of messages that could not be processed.</td>
-  </tr>
-  <tr>
-    <td><code>canonical_ids</code></td>
-    <td>Number of results that contain a canonical registration ID. See <a href="adv.html#canonical">Advanced Topics</a> for more discussion of this topic.</td>
-  </tr>
-  <tr>
-    <td><code>results</code></td>
-    <td>Array of objects representing the status of the messages processed. The objects are listed in the same order as the request (i.e., for each registration ID in the request, its result is listed in the same index in the response) and they can have these fields:<br>
-      <ul>
-        <li><code>message_id</code>: String representing the message when it was successfully processed.</li>
-        <li><code>registration_id</code>: If set,  means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.
-        </li>
-        <li><code>error</code>: String describing an error that occurred while processing the message for that recipient. The possible values are the same as documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers were busy and could not process the message for that  particular recipient, so it could be retried).</li>
-    </ul></td>
-  </tr>
-</table>
-<p>If the value of <code>failure</code> and <code>canonical_ids</code> is 0, it's not necessary to parse the remainder of the response. Otherwise, we recommend that you iterate through the results field and do the following for each object in that list:</p>
-<ul>
-  <li>If <code>message_id</code> is set, check for <code>registration_id</code>:
-    <ul>
-      <li>If <code>registration_id</code> is set, replace the original ID with the new value (canonical ID) in your server database. Note that the original ID is not part of the result, so you need to obtain it from the list of <code>registration_ids</code> passed in the request (using the same index).</li>
-    </ul>
-  </li>
-  <li>Otherwise, get the value of <code>error</code>:
-    <ul>
-      <li>If it is <code>Unavailable</code>, you could retry to send it in another request.</li>
-      <li>If it is <code>NotRegistered</code>, you should remove the registration ID from your server database because the application was uninstalled from the device or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
-      <li>Otherwise, there is something wrong in the registration ID passed in the request; it is probably a non-recoverable error that will also require removing the registration from the server database. See <a href="#error_codes">Interpreting an error response</a> for all possible error values.</li>
-    </ul>
-  </li>
-</ul>
-
-<p>When a plain-text request is successful (HTTP status code 200), the response body contains 1 or 2 lines in the form of key/value pairs.
-The first line is always available and its content is either <code>id=<em>ID of sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second line, if available, 
-has the format of <code>registration_id=<em>canonical ID</em></code>. The second line is optional, and it can only be sent if the first line is not an error. We recommend handling the plain-text response in a similar way as handling the JSON response:</p>
-<ul>
-  <li>If first line starts with <code>id</code>, check second line:
-    <ul>
-      <li>If second line starts with <code>registration_id</code>, gets its value and replace the registration IDs in your server database.</li>
-    </ul>
-  </li>
-  <li>Otherwise, get the value of <code>Error</code>:
-    <ul>
-      <li>If it is <code>NotRegistered</code>, remove the registration ID from your server database.</li>
-      <li>Otherwise, there is probably a non-recoverable error (<strong>Note: </strong>Plain-text requests will never return <code>Unavailable</code> as the error code, they would have returned a 500 HTTP status instead).</li>
-    </ul>
-  </li>
-</ul>
-
-<h4 id="error_codes">Interpreting an error response</h4>
-<p>Here are the recommendations for handling the different types of error that might occur when trying to send a message to a device:</p>
-
-<dl>
-<dt id="missing_reg"><strong>Missing Registration ID</strong></dt>
-<dd>Check that the request contains a registration ID (either in the <code>registration_id</code> parameter in a plain text message, or in the <code>registration_ids</code> field in JSON). 
-<br/>Happens when error code is <code>MissingRegistration</code>.</dd>
-
-<dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
-<dd>Check the formatting of the registration ID that you pass to the server. Make sure it matches the registration ID the phone receives in the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're not truncating it or adding additional characters. 
-<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
-
-<dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
-<dd>A registration ID is tied to a certain group of senders. When an application registers for GCM usage, it must specify which senders are allowed to send messages. Make sure you're using one of those when trying to send messages to the device. If you switch to a different sender, the existing registration IDs won't work. 
-Happens when error code is <code>MismatchSenderId</code>.</dd>
-
-<dt id="unreg_device"><strong>Unregistered Device</strong></dt>
-<dd>An existing registration ID may cease to be valid in a number of scenarios, including:
-<ul>
-  <li>If the application manually unregisters by issuing a <span class="prettyprint pretty-java"><code>com.google.android.c2dm.intent.UNREGISTER</code></span><code> </code>intent.</li>
-  <li>If the application is automatically unregistered, which can happen (but is not guaranteed) if the user uninstalls the application.</li>
-  <li>If the registration ID expires. Google might decide to refresh registration IDs. </li>
-  <li>If the application is updated but the new version does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
-</ul>
-For all these cases, you should remove this registration ID from the 3rd-party server and stop using it to send 
-messages. 
-<br/>Happens when error code is <code>NotRegistered</code>.</dd>
-
-<dt id="big_msg"><strong>Message Too Big</strong></dt>
-  <dd>The total size of the payload data that is included in a message can't exceed 4096 bytes. Note that this includes both the size of the keys as well as the values. 
-<br/>Happens when error code is <code>MessageTooBig</code>.</dd>
-
-<dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
-<dd>The payload data contains a key (such as <code>from</code> or any value prefixed by <code>google.</code>) that is used internally by GCM in the  <code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used. Note that some words (such as <code>collapse_key</code>) are also used by GCM but are allowed in the payload, in which case the payload value will be overridden by the GCM value. 
-<br />
-Happens when the error code is <code>InvalidDataKey</code>.</dd>
-
-<dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
-  <dd>The value for the Time to Live field must be an integer representing a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code is <code>InvalidTtl</code>.
-</dd>
-
-  <dt id="auth_error"><strong>Authentication Error</strong></dt>
-  <dd>The sender account that you're trying to use to send a message couldn't be authenticated. Possible causes are: <ul>
-<li>Authorization header missing or with invalid syntax.</li>
-<li>Invalid project number sent as key.</li>
-<li>Key valid but with GCM service disabled.</li>
-<li>Request originated from a server not whitelisted in the Server Key IPs.</li>
-
-</ul>
-Check that the token you're sending inside the <code>Authorization</code> header is the correct API key associated with your project. You can check the validity of your API key by running the following command:<br/>
-
-<pre># api_key=YOUR_API_KEY
-
-# curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"ABC\"]}"</pre>
-
-
-
-If you receive a 401 HTTP status code, your API key is not valid. Otherwise you should see something like this:<br/>
-
-<pre>
-{"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
-</pre>
-If you want to confirm the validity of a registration ID, you can do so by replacing "ABC" with the registration ID.
-<br/>
-Happens when the HTTP status code is 401.
-
-  <dt id="timeout"><strong>Timeout</strong></dt>
-
-<dd>The server couldn't process the request in time. You should retry the
-same request, but you MUST obey the following requirements:
-
-<ul>
-
-<li>Honor the <code>Retry-After</code> header if it's included in the response from the GCM server.</li>
-        
-        
-<li>Implement exponential back-off in your retry mechanism. This means an
-exponentially increasing delay after each failed retry (e.g. if you waited one
-second before the first retry, wait at least two second before the next one,
-then 4 seconds and so on). If you're sending multiple messages, delay each one
-independently by an additional random amount to avoid issuing a new request for
-all messages at the same time.</li>
-    
-
-Senders that cause problems risk being blacklisted. 
-<br />
-Happens when the HTTP status code is between 501 and 599, or when the <code>error</code> field of a JSON object in the results array is <code>Unavailable</code>.
-</dd>
-
-<dt id="internal_error"><strong>Internal Server Error</strong></dt>
-
-<dd>
-The server encountered an error while trying to process the request. You
-could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
-section), but if the error persists, please report the problem in the <a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
-<br />
-Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
-object in the results array is <code>InternalServerError</code>.
-</dd>
-
-<dt id="restricted_package_name"><strong>Invalid Package Name</strong></dt>
-
-<dd>
-A message was addressed to a registration ID whose package name did not match the value passed in the request. Happens when error code is 
-<code>InvalidPackageName</code>.
-</dd>
-
-
-</dl>
-<h4>Example responses</h4>
-<p>This section shows a few examples of responses indicating messages that were processed successfully. See <a href="#example-requests">Example requests</a> for the requests these responses are based on.</p>
-<p> Here is a simple case of a JSON message successfully sent to one recipient without canonical IDs in the response:</p>
-<pre class="prettyprint pretty-json">{ "multicast_id": 108,
-  "success": 1,
-  "failure": 0,
-  "canonical_ids": 0,
-  "results": [
-    { "message_id": "1:08" }
-  ]
-}</pre>
-
-<p>Or if the request was in plain-text format:</p>
-<pre class="prettyprint">id=1:08
-</pre>
-
-<p>Here are JSON results for 6 recipients (IDs 4, 8, 15, 16, 23, and 42 respectively) with 3 messages successfully processed, 1 canonical registration ID returned, and 3 errors:</p>
-<pre class="prettyprint pretty-json">{ "multicast_id": 216,
-  "success": 3,
-  "failure": 3,
-  "canonical_ids": 1,
-  "results": [
-    { "message_id": "1:0408" },
-    { "error": "Unavailable" },
-    { "error": "InvalidRegistration" },
-    { "message_id": "1:1516" },
-    { "message_id": "1:2342", "registration_id": "32" },
-    { "error": "NotRegistered"}
-  ]
-}
-</pre>
-<p> In this example:</p>
-<ul>
-  <li>First message: success, not required.</li>
-  <li>Second message: should be resent (to registration ID 8).</li>
-  <li>Third message: had an unrecoverable error (maybe the value got corrupted in the database).</li>
-  <li>Fourth message: success, nothing required.</li>
-  <li>Fifth message: success, but the registration ID should be updated in the server database (from 23 to 32).</li>
-  <li>Sixth message: registration ID (42) should be removed from the server database because the application was uninstalled from the device.</li>
-</ul>
-<p>Or if just the 4th message above was sent using plain-text format:</p>
-<pre class="prettyprint">Error=InvalidRegistration
-</pre>
-<p>If the 5th message above was also sent using plain-text format:</p>
-<pre class="prettyprint">id=1:2342
-registration_id=32
-</pre>
-
-<h3 id="stats">Viewing Statistics</h3>
-
-<p>To view  statistics and any error messages for your GCM applications:</p>
-<ol>
-  <li> Go to the <code><a href="http://play.google.com/apps/publish">Developer Console</a></code>.</li>
-  <li>Login with your developer account. 
-  <p>You will see a page that has a list of all of your apps.</p></li>
-  <li> Click on the &quot;statistics&quot; link next to the app for which you want to view GCM stats. 
-  <p>Now you are on the statistics page.</p> </li>
-  <li>Go to the drop-down menu and select the GCM metric you want to view. 
-  </li>
-</ol>
-<p class="note"><strong>Note:</strong> Stats on the Google API Console are not enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>
-
 
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index 8ceea0cc..3700f3f 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -1,5 +1,5 @@
-page.title=Getting Started with GCM
-page.tags="cloud","push","messaging"
+page.title=Getting Started
+page.tags=cloud,push,messaging
 @jd:body
 
 <div id="qv-wrapper">
@@ -12,8 +12,7 @@
 <li><a href="#create-proj">Creating a Google API Project</a></li>
 <li><a href="#gcm-service">Enabling the GCM Service</a></li>
 <li><a href="#access-key">Obtaining an API Key</a></li>
-<li><a href="#client">Writing a Client App</a></li>
-<li><a href="#server">Writing the Server Code</a></li>
+<li><a href="#next">Next Steps</a></li>
 </ol>
 
 <h2>See Also</h2>
@@ -26,12 +25,12 @@
 </div>
 </div>
 
-<p>The sections below guide you through the process of setting up a GCM
+<p>This document tells you how to get started setting up a GCM
 implementation.
-Before you start, make sure to <a href="/google/play-services/setup.html">set up
-the Google Play Services SDK</a>. You need this SDK to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> methods.</p>
-
-<p>Note that a full GCM implementation requires a server-side implementation, in addition to the client implementation in your app. This document offers a complete example that includes both the client and server.</p>
+Before you begin, make sure to <a href="/google/play-services/setup.html">set up
+the Google Play Services SDK</a>. You need this SDK to use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> methods.</p>
 
 
 <h2 id="create-proj">Creating a Google API project</h2>
@@ -41,13 +40,17 @@
   </li>
   <li>If you haven't created an API project yet, this page will prompt you to do so:
   <p><img src="{@docRoot}images/gcm/gcm-create-api-proj.png" class="screenshot" /></p>
-<p class="note"><strong>Note:</strong> If you already have existing projects, the first page you see will be the <strong>Dashboard</strong> page. From there you can create a new project by opening the project drop-down menu (upper left corner) and choosing <strong>Other projects > Create</strong>.</p></li>
+<p class="note"><strong>Note:</strong> If you already have existing projects,
+the first page you see will be the <strong>Dashboard</strong> page. From there
+you can create a new project by opening the project drop-down menu (upper left corner)
+and choosing <strong>Other projects > Create</strong>.</p></li>
   <li> Click <strong>Create project</strong>.
     Your browser URL will change to something like:</li>
 
 <pre> https://code.google.com/apis/console/#project:<strong>4815162342</strong></pre>
 
-  <li> Take note of the value after <code>#project:</code> (4815162342 in this example). This is your project number, and it will be used later on as the GCM sender ID.</li>
+  <li> Take note of the value after <code>#project:</code> (4815162342 in this
+example). This is your project number, and it will be used later on as the GCM sender ID.</li>
   
 </ol>
 <h2 id="gcm-service">Enabling the GCM Service</h2>
@@ -61,463 +64,53 @@
 <h2 id="access-key">Obtaining an API Key</h2>
 <p>To obtain an API  key:</p>
 <ol>
-  <li> In the main Google APIs Console page, select <strong>API Access</strong>. You will see a screen that resembles the following:</li><br />
+  <li> In the main Google APIs Console page, select <strong>API Access</strong>.
+You will see a screen that resembles the following:</li>
 
 
-<img src="{@docRoot}images/gcm/gcm-api-access.png" style="width:400px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/gcm/gcm-api-access.png" style="width:400px;padding:4px;">
+
+  <li>Click  <strong>Create new Server key</strong>. Either a server key or a
+browser key should work. The advantage to using a server key is that it allows
+you to whitelist IP addresses. The following screen appears:</li>
 
 
-  <li>Click  <strong>Create new Server key</strong>. Either a server key or a browser key should work. The advantage to using a server key is that it allows you to whitelist IP addresses. The following screen appears:</li><br />
-
-
-<img src="{@docRoot}images/gcm/gcm-config-server-key.png" style="width:400px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/gcm/gcm-config-server-key.png" style="width:400px;padding:4px;">
 
   
-  <li>Click <strong>Create</strong>:</li><br />
+  <li>Click <strong>Create</strong>:</li>
   
 
-<img src="{@docRoot}images/gcm/gcm-api-key.png" style="width:400px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/gcm/gcm-api-key.png" style="width:400px;padding:4px;">
 
 
 
 </ol>
-<p> Take note of the <strong>API key</strong> value (<code>YourKeyWillBeShownHere</code>) in this example, as it will be used later on.</p>
-<p class="note"><strong>Note:</strong> If you need to rotate the key, click  <strong>Generate new key</strong>. A new key  will be created while the old one will still be active for up to 24 hours. If you want to get rid of the old key immediately (for example, if you feel it was compromised), click <strong>Delete key</strong>.</p>
+<p> Take note of the <strong>API key</strong> value (<code>YourKeyWillBeShownHere</code>)
+in this example, as it will be used later on.</p>
+<p class="note"><strong>Note:</strong> If you need to rotate the key, click
+<strong>Generate new key</strong>. A new key  will be created while the old one
+will still be active for up to 24 hours. If you want to get rid of the old key
+immediately (for example, if you feel it was compromised), click <strong>Delete key</strong>.</p>
 
-<p>The following sections walk you through the steps of creating client and server-side code.</p>
+<h2 id="next">Next Steps</h2>
 
-<h2 id="client">Writing a Client App</h2>
+<p>Once you've finished the tasks listed above, you're ready to start
+implementing GCM. Here is an overview of the basic steps:</p>
 
-<p>This section walks you through the steps involved in writing a client-side application&mdash;that is, the GCM-enabled application that runs on an Android device. This client sample is designed to work in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>, below.</p>
-
-
-
-<h3 id="manifest">Step 1: Edit Your App's Manifest</h3>
-<ul>
-  <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so the Android application can register and receive messages.</li>
-  <li>The <code>android.permission.INTERNET</code> permission so the Android application can send the registration ID to the 3rd party server.</li>
-  <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4)</li>
-  <li>The <code>android.permission.WAKE_LOCK</code> permission so the application can keep the processor from sleeping when a message is received. Optional&mdash;use only if the app wants to keep the device from sleeping.</li>
-  <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code> permission to prevent other Android applications from registering and receiving the Android application's
-messages. The permission name must exactly match this pattern&mdash;otherwise the Android application will not receive the messages.</li>
-   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with the category set
-as <code>applicationPackage</code>. The receiver should require the <code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
-Framework can send a message to it. Note that the receiving
-of messages is implemented as an <a href="{@docRoot}guide/components/intents-filters.html">intent</a>.</li>
-  <li>An intent service to handle the intents received by the broadcast receiver. Optional.</li>
-  <li>If the GCM feature is critical to the Android application's function, be sure to
-set <code>android:minSdkVersion=&quot;8&quot;</code> in the manifest. This
-ensures that the Android application cannot be installed in an environment in which it
-could not run properly. </li>
-</ul>
-
-<p>Here are excerpts from a manifest that supports GCM:</p>
-
-<pre class="prettyprint pretty-xml">
-&lt;manifest package="com.example.gcm" ...&gt;
-
-    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
-    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
-    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
-    &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
-    &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
-
-    &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE" 
-        android:protectionLevel="signature" /&gt;
-    &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
-
-    &lt;application ...&gt;
-        &lt;receiver
-            android:name=".MyBroadcastReceiver"
-            android:permission="com.google.android.c2dm.permission.SEND" &gt;
-            &lt;intent-filter&gt;
-                &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
-                &lt;category android:name="com.example.gcm" /&gt;
-            &lt;/intent-filter&gt;
-        &lt;/receiver&gt;
-        &lt;service android:name=".MyIntentService" /&gt;
-    &lt;/application&gt;
-
-&lt;/manifest&gt;
-</pre>
-
-
-<h3 id="register">Step 2: Register for GCM</h3>
-
-<p>An Android application running on a mobile device registers to receive messages by calling 
-the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> method 
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register">{@code register(senderID...)}</a>.
-This method registers the application for GCM and returns the registration ID. This streamlined approach replaces the previous
-GCM registration process. See the example below for details.</p>
-
-<h3 id="app"> Step 3: Write Your Application</h3>
-
-<p>Finally, write your application. GCM offers a variety of ways to get the job done:</p>
-
-<ul>
-  <li>For your messaging server, you can either use the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), the older <a href="gcm.html">GCM HTTP server</a>, or both in tandem. For more discussion, see see <a href="server.html">GCM Server</a>.</li>
-  <li>To write your client application (that is, the GCM-enabled app that runs on an Android device), use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs as shown below. Don't forget to set up your project to use the Google Play services SDK as described in <a href="/google/play-services/setup.html">Setup Google Play Services SDK</a>.</li>
-</ul>
-</li>
-  
-</ul>
-
-<h4 id="example">Example</h4>
-
-<p>Here is a sample client application that illustrates how to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. The sample consists of a main activity ({@code DemoActivity}) and a broadcast receiver ({@code GcmBroadcastReceiver}). You can use this client sample code in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>.</p>
-
-<p>Note the following:</p>
-
-<ul>
-  <li>The sample primarily illustrates two things: registration, and upstream messaging. Upstream messaging only applies to apps that are running against a <a href="ccs.html">CCS</a> server; HTTP-based servers don't support upstream messaging.</li>
-  <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> registration APIs replace the old registration process, which was based on the now-obsolete client helper library. While the old registration process still works, we encourage you to use the newer <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> registration APIs, regardless of your underlying server.</li>
-</ul>
-
-<h5>Registering</h5>
-<p>An Android application needs to register with GCM servers before it can receive messages. So in its {@code onCreate()} method, {@code DemoActivity} checks to see whether the app is registered with GCM and with the server:</p>
-
-<pre>/**
- * Main UI for the demo app.
- */
-public class DemoActivity extends Activity {
-
-    public static final String EXTRA_MESSAGE = "message";
-    public static final String PROPERTY_REG_ID = "registration_id";
-    private static final String PROPERTY_APP_VERSION = "appVersion";
-    private static final String PROPERTY_ON_SERVER_EXPIRATION_TIME =
-            "onServerExpirationTimeMs";
-    /**
-     * Default lifespan (7 days) of a reservation until it is considered expired.
-     */
-    public static final long REGISTRATION_EXPIRY_TIME_MS = 1000 * 3600 * 24 * 7;
-
-    /**
-     * Substitute you own sender ID here.
-     */
-    String SENDER_ID = "Your-Sender-ID";
-
-    /**
-     * Tag used on log messages.
-     */
-    static final String TAG = "GCMDemo";
-
-    TextView mDisplay;
-    GoogleCloudMessaging gcm;
-    AtomicInteger msgId = new AtomicInteger();
-    SharedPreferences prefs;
-    Context context;
-
-    String regid;
-
-    &#64;Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.main);
-        mDisplay = (TextView) findViewById(R.id.display);
-
-        context = getApplicationContext();
-        regid = getRegistrationId(context);
-
-        if (regid.length() == 0) {
-            registerBackground();
-        }
-        gcm = GoogleCloudMessaging.getInstance(this);
-    }
-...
-}</pre>
-
-<p>The app calls {@code getRegistrationId()} to see whether there is an existing registration ID stored in shared preferences:</p>
-
-<pre>/**
- * Gets the current registration id for application on GCM service.
- * &lt;p&gt;
- * If result is empty, the registration has failed.
- *
- * &#64;return registration id, or empty string if the registration is not
- *         complete.
- */
-private String getRegistrationId(Context context) {
-    final SharedPreferences prefs = getGCMPreferences(context);
-    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
-    if (registrationId.length() == 0) {
-        Log.v(TAG, "Registration not found.");
-        return "";
-    }
-    // check if app was updated; if so, it must clear registration id to
-    // avoid a race condition if GCM sends a message
-    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
-    int currentVersion = getAppVersion(context);
-    if (registeredVersion != currentVersion || isRegistrationExpired()) {
-        Log.v(TAG, "App version changed or registration expired.");
-        return "";
-    }
-    return registrationId;
-}
-
-...
-
-/**
- * &#64;return Application's {&#64;code SharedPreferences}.
- */
-private SharedPreferences getGCMPreferences(Context context) {
-    return getSharedPreferences(DemoActivity.class.getSimpleName(), 
-            Context.MODE_PRIVATE);
-}</pre>
-
-<p>If the registration ID doesn't exist, or the app was updated, or the registration ID has expired, {@code getRegistrationId()} returns an empty string to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls the following methods to check the app version and whether the regID has expired:</p>
-
-<pre>/**
- * &#64;return Application's version code from the {&#64;code PackageManager}.
- */
-private static int getAppVersion(Context context) {
-    try {
-        PackageInfo packageInfo = context.getPackageManager()
-                .getPackageInfo(context.getPackageName(), 0);
-        return packageInfo.versionCode;
-    } catch (NameNotFoundException e) {
-        // should never happen
-        throw new RuntimeException("Could not get package name: " + e);
-    }
-}
-
-/**
- * Checks if the registration has expired.
- *
- * &lt;p&gt;To avoid the scenario where the device sends the registration to the
- * server but the server loses it, the app developer may choose to re-register
- * after REGISTRATION_EXPIRY_TIME_MS.
- *
- * &#64;return true if the registration has expired.
- */
-private boolean isRegistrationExpired() {
-    final SharedPreferences prefs = getGCMPreferences(context);
-    // checks if the information is not stale
-    long expirationTime =
-            prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
-    return System.currentTimeMillis() > expirationTime;
-}</pre>
-
-
-<p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the following {@code registerBackground()} method to register. Note that because GCM methods are blocking, this has to take place on a background thread. This sample uses {@link android.os.AsyncTask} to accomplish this:</p>
-
-<pre>
-/**
- * Registers the application with GCM servers asynchronously.
- * &lt;p&gt;
- * Stores the registration id, app versionCode, and expiration time in the 
- * application's shared preferences.
- */
-private void registerBackground() {
-    new AsyncTask<Void, Void, String>() {
-        &#64;Override
-        protected String doInBackground(Void... params) {
-            String msg = "";
-            try {
-                if (gcm == null) {
-                    gcm = GoogleCloudMessaging.getInstance(context);
-                }
-                regid = gcm.register(SENDER_ID);
-                msg = "Device registered, registration id=" + regid;
-
-                // You should send the registration ID to your server over HTTP,
-                // so it can use GCM/HTTP or CCS to send messages to your app.
-
-                // For this demo: we don't need to send it because the device
-                // will send upstream messages to a server that echo back the message
-                // using the 'from' address in the message.
-
-                // Save the regid - no need to register again.
-                setRegistrationId(context, regid);
-            } catch (IOException ex) {
-                msg = "Error :" + ex.getMessage();
-            }
-            return msg;
-        }
-
-        &#64;Override
-        protected void onPostExecute(String msg) {
-            mDisplay.append(msg + "\n");
-        }
-    }.execute(null, null, null);
-}</pre>
-
-<p>After registering, the app calls {@code setRegistrationId()} to store the registration ID in shared preferences for future use:</p>
-
-<pre>/**
- * Stores the registration id, app versionCode, and expiration time in the
- * application's {&#64;code SharedPreferences}.
- *
- * &#64;param context application's context.
- * &#64;param regId registration id
- */
-private void setRegistrationId(Context context, String regId) {
-    final SharedPreferences prefs = getGCMPreferences(context);
-    int appVersion = getAppVersion(context);
-    Log.v(TAG, "Saving regId on app version " + appVersion);
-    SharedPreferences.Editor editor = prefs.edit();
-    editor.putString(PROPERTY_REG_ID, regId);
-    editor.putInt(PROPERTY_APP_VERSION, appVersion);
-    long expirationTime = System.currentTimeMillis() + REGISTRATION_EXPIRY_TIME_MS;
-
-    Log.v(TAG, "Setting registration expiry time to " +
-            new Timestamp(expirationTime));
-    editor.putLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, expirationTime);
-    editor.commit();
-}</pre>
-
-<h5>Sending a message</h5>
-<p>When the user clicks the app's <strong>Send</strong> button, the app sends an upstream message using the new <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. In order to receive the upstream message, your server should be connected to CCS. You can use the code shown in <a href="#server">Writing the Server Code</a> as a sample XMPP client to connect to CCS.</p>
-
-<pre>public void onClick(final View view) {
-    if (view == findViewById(R.id.send)) {
-        new AsyncTask<Void, Void, String>() {
-            &#64;Override
-            protected String doInBackground(Void... params) {
-                String msg = "";
-                try {
-                    Bundle data = new Bundle();
-                    data.putString("hello", "World");
-                    String id = Integer.toString(msgId.incrementAndGet());
-                    gcm.send(SENDER_ID + "&#64;gcm.googleapis.com", id, data);
-                    msg = "Sent message";
-                } catch (IOException ex) {
-                    msg = "Error :" + ex.getMessage();
-                }
-                return msg;
-            }
-
-            &#64;Override
-            protected void onPostExecute(String msg) {
-                mDisplay.append(msg + "\n");
-            }
-        }.execute(null, null, null);
-    } else if (view == findViewById(R.id.clear)) {
-        mDisplay.setText("");
-    } 
-}</pre>
-
-<p>As described above in <a href="#manifest">Step 1</a>, the app includes a broadcast receiver for the <code>com.google.android.c2dm.intent.RECEIVE</code> intent. This is the mechanism GCM uses to deliver messages. When {@code onClick()} calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()} method, which has the responsibility of handling the GCM message. In this sample the receiver's {@code onReceive()} method calls {@code sendNotification()} to put the message into a notification:</p>
-
-<pre>/**
- * Handling of GCM messages.
- */
-public class GcmBroadcastReceiver extends BroadcastReceiver {
-    static final String TAG = "GCMDemo";
-    public static final int NOTIFICATION_ID = 1;
-    private NotificationManager mNotificationManager;
-    NotificationCompat.Builder builder;
-    Context ctx;
-    &#64;Override
-    public void onReceive(Context context, Intent intent) {
-        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
-        ctx = context;
-        String messageType = gcm.getMessageType(intent);
-        if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
-            sendNotification("Send error: " + intent.getExtras().toString());
-        } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
-            sendNotification("Deleted messages on server: " +
-                    intent.getExtras().toString());
-        } else {
-            sendNotification("Received: " + intent.getExtras().toString());
-        }
-        setResultCode(Activity.RESULT_OK);
-    }
-
-    // Put the GCM message into a notification and post it.
-    private void sendNotification(String msg) {
-        mNotificationManager = (NotificationManager)
-                ctx.getSystemService(Context.NOTIFICATION_SERVICE);
-
-        PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
-                new Intent(ctx, DemoActivity.class), 0);
-
-        NotificationCompat.Builder mBuilder =
-                new NotificationCompat.Builder(ctx)
-        .setSmallIcon(R.drawable.ic_stat_gcm)
-        .setContentTitle("GCM Notification")
-        .setStyle(new NotificationCompat.BigTextStyle()
-        .bigText(msg))
-        .setContentText(msg);
-
-        mBuilder.setContentIntent(contentIntent);
-        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
-    }
-}</pre>
-
-<h2 id="server">Writing the Server Code</h2>
-
-<p>Here is an example of a CCS server written in Python. You can use this in conjunction with the sample client code shown above. This sample echo server sends an initial message, and for every upstream message received, it sends a dummy response back to the application that sent the upstream message. This example illustrates how to connect,
-send, and receive GCM messages using XMPP. It shouldn't be used as-is
-on a production deployment. For examples of HTTP-based servers, see <a href="server.html">GCM Server</a>.</p>
-
-<pre>
-#!/usr/bin/python
-import sys, json, xmpp, random, string
-
-SERVER = 'gcm.googleapis.com'
-PORT = 5235
-USERNAME = ''
-PASSWORD = ''
-REGISTRATION_ID = ''
-
-unacked_messages_quota = 1000
-send_queue = []
-
-# Return a random alphanumerical id
-def random_id():
-  rid = ''
-  for x in range(8): rid += random.choice(string.ascii_letters + string.digits)
-  return rid
-
-def message_callback(session, message):
-  global unacked_messages_quota
-  gcm = message.getTags('gcm')
-  if gcm:
-    gcm_json = gcm[0].getData()
-    msg = json.loads(gcm_json)
-    if not msg.has_key('message_type'):
-      # Acknowledge the incoming message immediately.
-      send({'to': msg['from'],
-            'message_type': 'ack',
-            'message_id': msg['message_id']})
-      # Queue a response back to the server.
-      if msg.has_key('from'):
-        # Send a dummy echo response back to the app that sent the upstream message.
-        send_queue.append({'to': msg['from'],
-                           'message_id': random_id(),
-                           'data': {'pong': 1}})
-    elif msg['message_type'] == 'ack' or msg['message_type'] == 'nack':
-      unacked_messages_quota += 1
-
-def send(json_dict):
-  template = (&quot;&lt;message&gt;&lt;gcm xmlns='google:mobile:data'&gt;{1}&lt;/gcm&gt;&lt;/message&gt;&quot;)
-  client.send(xmpp.protocol.Message(
-      node=template.format(client.Bind.bound[0], json.dumps(json_dict))))
-
-def flush_queued_messages():
-  global unacked_messages_quota
-  while len(send_queue) and unacked_messages_quota &gt; 0:
-    send(send_queue.pop(0))
-    unacked_messages_quota -= 1
-
-client = xmpp.Client('gcm.googleapis.com', debug=['socket'])
-client.connect(server=(SERVER,PORT), secure=1, use_srv=False)
-auth = client.auth(USERNAME, PASSWORD)
-if not auth:
-  print 'Authentication failed!'
-  sys.exit(1)
-
-client.RegisterHandler('message', message_callback)
-
-send_queue.append({'to': REGISTRATION_ID,
-                   'message_id': 'reg_id',
-                   'data': {'message_destination': 'RegId',
-                            'message_id': random_id()}})
-
-while True:
-  client.Process(1)
-  flush_queued_messages()</pre>
-
+<ol>
+  <li>Decide which Google-provided GCM connection server you want to use&mdash;
+  <a href="http.html">HTTP</a> or <a href="ccs.html">XMPP</a> (CCS). GCM connection servers
+take messages from a 3rd-party application
+server (written by you) and send them to a GCM-enabled Android application (the
+"client app," also written by you) running on a device. </li>
+  <li>Implement an application server (the "3rd-party application server") to interact
+with your chosen GCM connection server. The app server sends data to a
+GCM-enabled Android client application via the GCM connection server. For more
+information about implementing the server side, see <a href="server.html">
+Implementing GCM Server</a>.</li>
+<li>Write your client app. This is the GCM-enabled Android application that runs
+on a device. See <a href="client.html">Implementing GCM Client</a> for more information.</li>
+</ol>
 
 
diff --git a/docs/html/google/gcm/helper.jd b/docs/html/google/gcm/helper.jd
index e7f2f73..19dcdc5 100644
--- a/docs/html/google/gcm/helper.jd
+++ b/docs/html/google/gcm/helper.jd
@@ -1,5 +1,5 @@
 page.title=Using the GCM Helper Libraries
-page.tags="cloud","push","messaging"
+page.tags=cloud,push,messaging
 @jd:body
 
 <div id="deprecatedSticker">
diff --git a/docs/html/google/gcm/http.jd b/docs/html/google/gcm/http.jd
new file mode 100644
index 0000000..b8d8659
--- /dev/null
+++ b/docs/html/google/gcm/http.jd
@@ -0,0 +1,618 @@
+page.title=GCM HTTP Connection Server
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+
+<h2>In this document</h2>
+
+<ol class="toc">
+  <li><a href="#auth">Authentication</a> </li>
+  <li><a href="#request">Request Format</a> </li>
+  <li><a href="#response">Response Format</a>
+  <ol class="toc">
+    <li><a href="#success">Interpreting a success response</a>
+    <li><a href="#error_codes">Interpreting an error response</a>
+    <li><a href="#example-responses">Example responses</a>
+  </ol>
+  </li>
+  <li><a href="#app-server">Implementing an HTTP-Based App Server</a>
+</ol>
+
+<h2>See Also</h2>
+
+<ol class="toc">
+<li><a href="gs.html">Getting Started</a></li>
+<li><a href="client.html">Implementing GCM Client</a></li>
+<li><a href="ccs.html">Cloud Connection Server</a></li>
+
+
+</ol>
+
+</div>
+</div>
+
+<p>This document describes the GCM HTTP connection server. Connection servers
+are the Google-provided servers that take messages from the 3rd-party
+application server and sending them to the device.</p>
+
+
+
+<p class="note"><strong>Note:</strong> See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+parameters and which connection server(s) supports them.</p>
+
+
+<h2 id="auth">Authentication</h2>
+
+<p>To send a  message, the application server issues a POST request to
+<code>https://android.googleapis.com/gcm/send</code>.</p>
+<p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
+
+<p>The HTTP header must contain the following headers:</p>
+<ul>
+  <li><code>Authorization</code>: key=YOUR_API_KEY</li>
+  <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
+  </li>
+</ul>
+
+<p>For example:
+</p>
+<pre>Content-Type:application/json
+Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
+
+{
+  "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
+  "data" : {
+    ...
+  },
+}</pre>
+<p class="note">
+  <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format
+is assumed to be plain text.</p>
+</p>
+
+<p>The HTTP body content depends on whether you're using JSON or plain text.
+See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the
+parameters your JSON or plain text message can contain.</p>
+
+
+  <h2 id="request">Request Format</h2>
+  <p>Here is the smallest possible request (a message without any parameters and
+just one recipient) using JSON:</p>
+  <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
+
+  <p>And here the same example using plain text:</p>
+  <pre class="prettyprint">registration_id=42</pre>
+
+  <p> Here is a message with a payload and 6 recipients:</p>
+  <pre class="prettyprint pretty-HTML">{ "data": {
+    "score": "5x1",
+    "time": "15:10"
+  },
+  "registration_ids": ["4", "8", "15", "16", "23", "42"]
+}</pre>
+  <p>Here is a message with all optional fields set and 6 recipients:</p>
+  <pre class="prettyprint pretty-json">{ "collapse_key": "score_update",
+  "time_to_live": 108,
+  "delay_while_idle": true,
+  "data": {
+    "score": "4x8",
+    "time": "15:16.2342"
+  },
+  "registration_ids":["4", "8", "15", "16", "23", "42"]
+}</pre>
+  <p>And here is the same message using plain-text format (but just 1 recipient):  </p>
+
+  <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
+  </pre>
+
+<p class="note"><strong>Note:</strong> If your organization has a firewall
+that restricts the traffic to or
+from the Internet, you need to configure it to allow connectivity with GCM in order for
+your Android devices to receive messages.
+The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
+it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
+your firewall to accept outgoing connections to all IP addresses
+contained in the IP blocks listed in Google's ASN of 15169.</p>
+
+
+
+<h2 id="response">Response format</h2>
+
+<p>There are two possible outcomes when trying to send a message:</p>
+<ul>
+  <li>The message is processed successfully.</li>
+  <li>The GCM server rejects the request.</li>
+</ul>
+
+<p>When the message is processed successfully, the HTTP response has a 200 status
+and the body contains more information about the status of the message
+(including possible errors). When the request is rejected,
+the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
+
+<p>The following table summarizes the statuses that the HTTP response header might
+contain. Click the troubleshoot link for advice on how to deal with each type of
+error.</p>
+<table border=1>
+  <tr>
+    <th>Response</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>Message was processed successfully. The response body will contain more
+details about the message status, but its format will depend whether the request
+was JSON or plain text. See <a href="#success">Interpreting a success response</a>
+for more details.</td>
+  </tr>
+  <tr>
+    <td>400</td>
+    <td><span id="internal-source-marker_0.2">Only applies for JSON requests.
+Indicates that the request could not be parsed as JSON, or it contained invalid
+fields (for instance, passing a string where a number was expected). The exact
+failure reason is described in the response and the problem should be addressed
+before the request can be retried.</td>
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>There was an error authenticating the sender account.
+<a href="#auth_error">Troubleshoot</a></td>
+  </tr>
+  <tr>
+    <td>5xx</td>
+    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there wa
+an internal error in the GCM server while trying to process the request, or that
+the server is temporarily unavailable (for example, because of timeouts). Sender
+must retry later, honoring any <code>Retry-After</code> header included in the
+response. Application servers must implement exponential back-off.
+<a href="#internal_error">Troubleshoot</a></td>
+  </tr>
+</table>
+
+<h3 id="success">Interpreting a success response</h3>
+<p>When a JSON request is successful (HTTP status code 200), the response body
+contains a JSON object with the following fields:</p>
+<table>
+  <tr>
+    <th>Field</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>multicast_id</code></td>
+    <td>Unique ID (number) identifying the multicast message.</td>
+  </tr>
+  <tr>
+    <td><code>success</code></td>
+    <td>Number of messages that were processed without an error.</td>
+  </tr>
+  <tr>
+    <td><code>failure</code></td>
+    <td>Number of messages that could not be processed.</td>
+  </tr>
+  <tr>
+    <td><code>canonical_ids</code></td>
+    <td>Number of results that contain a canonical registration ID. See
+<a href="adv.html#canonical">Advanced Topics</a> for more discussion of this topic.</td>
+  </tr>
+  <tr>
+    <td><code>results</code></td>
+    <td>Array of objects representing the status of the messages processed. The
+objects are listed in the same order as the request (i.e., for each registration
+ID in the request, its result is listed in the same index in the response) and
+they can have these fields:<br>
+      <ul>
+        <li><code>message_id</code>: String representing the message when it was
+successfully processed.</li>
+        <li><code>registration_id</code>: If set,  means that GCM processed the
+message but it has another canonical registration ID for that device, so sender
+should replace the IDs on future requests (otherwise they might be rejected).
+This field is never set if there is an error in the request.
+        </li>
+        <li><code>error</code>: String describing an error that occurred while
+processing the message for that recipient. The possible values are the same as
+documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers
+were busy and could not process the message for that  particular recipient, so
+it could be retried).</li>
+    </ul></td>
+  </tr>
+</table>
+<p>If the value of <code>failure</code> and <code>canonical_ids</code> is 0, it's
+not necessary to parse the remainder of the response. Otherwise, we recommend
+that you iterate through the results field and do the following for each object
+in that list:</p>
+<ul>
+  <li>If <code>message_id</code> is set, check for <code>registration_id</code>:
+    <ul>
+      <li>If <code>registration_id</code> is set, replace the original ID with
+the new value (canonical ID) in your server database. Note that the original ID
+is not part of the result, so you need to obtain it from the list of
+code>registration_ids</code> passed in the request (using the same index).</li>
+    </ul>
+  </li>
+  <li>Otherwise, get the value of <code>error</code>:
+    <ul>
+      <li>If it is <code>Unavailable</code>, you could retry to send it in another
+request.</li>
+      <li>If it is <code>NotRegistered</code>, you should remove the registration
+ID from your server database because the application was uninstalled from the
+device or it does not have a broadcast receiver configured to receive
+<code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
+      <li>Otherwise, there is something wrong in the registration ID passed in
+the request; it is probably a non-recoverable error that will also require removing
+the registration from the server database. See <a href="#error_codes">Interpreting
+an error response</a> for all possible error values.</li>
+    </ul>
+  </li>
+</ul>
+
+<p>When a plain-text request is successful (HTTP status code 200), the response
+body contains 1 or 2 lines in the form of key/value pairs.
+The first line is always available and its content is either <code>id=<em>ID of
+sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second
+line, if available,
+has the format of <code>registration_id=<em>canonical ID</em></code>. The second
+line is optional, and it can only be sent if the first line is not an error. We
+recommend handling the plain-text response in a similar way as handling the
+JSON response:</p>
+<ul>
+  <li>If first line starts with <code>id</code>, check second line:
+    <ul>
+      <li>If second line starts with <code>registration_id</code>, gets its value
+and replace the registration IDs in your server database.</li>
+    </ul>
+  </li>
+  <li>Otherwise, get the value of <code>Error</code>:
+    <ul>
+      <li>If it is <code>NotRegistered</code>, remove the registration ID from
+your server database.</li>
+      <li>Otherwise, there is probably a non-recoverable error (<strong>Note:
+</strong>Plain-text requests will never return <code>Unavailable</code> as the
+error code, they would have returned a 500 HTTP status instead).</li>
+    </ul>
+  </li>
+</ul>
+
+<h3 id="error_codes">Interpreting an error response</h3>
+<p>Here are the recommendations for handling the different types of error that
+might occur when trying to send a message to a device:</p>
+
+<dl>
+<dt id="missing_reg"><strong>Missing Registration ID</strong></dt>
+<dd>Check that the request contains a registration ID (either in the
+<code>registration_id</code> parameter in a plain text message, or in the
+<code>registration_ids</code> field in JSON).
+<br/>Happens when error code is <code>MissingRegistration</code>.</dd>
+
+<dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
+<dd>Check the formatting of the registration ID that you pass to the server. Make
+sure it matches the registration ID the phone receives in the
+<code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're
+not truncating it or adding additional characters.
+<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
+
+<dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
+<dd>A registration ID is tied to a certain group of senders. When an application
+registers for GCM usage, it must specify which senders are allowed to send messages.
+Make sure you're using one of those when trying to send messages to the device.
+If you switch to a different sender, the existing registration IDs won't work.
+Happens when error code is <code>MismatchSenderId</code>.</dd>
+
+<dt id="unreg_device"><strong>Unregistered Device</strong></dt>
+<dd>An existing registration ID may cease to be valid in a number of scenarios, including:
+<ul>
+  <li>If the application manually unregisters by issuing a
+<span class="prettyprint pretty-java">
+<code>com.google.android.c2dm.intent.UNREGISTER</code></span><code>
+</code>intent.</li>
+  <li>If the application is automatically unregistered, which can happen
+(but is not guaranteed) if the user uninstalls the application.</li>
+  <li>If the registration ID expires. Google might decide to refresh registration
+IDs. </li>
+  <li>If the application is updated but the new version does not have a broadcast
+receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code>
+intents.</li>
+</ul>
+For all these cases, you should remove this registration ID from the 3rd-party
+server and stop using it to send
+messages.
+<br/>Happens when error code is <code>NotRegistered</code>.</dd>
+
+<dt id="big_msg"><strong>Message Too Big</strong></dt>
+  <dd>The total size of the payload data that is included in a message can't
+exceed 4096 bytes. Note that this includes both the size of the keys as well
+as the values.
+<br/>Happens when error code is <code>MessageTooBig</code>.</dd>
+
+<dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
+<dd>The payload data contains a key (such as <code>from</code> or any value
+prefixed by <code>google.</code>) that is used internally by GCM in the
+<code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used.
+Note that some words (such as <code>collapse_key</code>) are also used by GCM
+but are allowed in the payload, in which case the payload value will be
+overridden by the GCM value.
+<br />
+Happens when the error code is <code>InvalidDataKey</code>.</dd>
+
+<dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
+  <dd>The value for the Time to Live field must be an integer representing
+a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code
+is <code>InvalidTtl</code>.
+</dd>
+
+  <dt id="auth_error"><strong>Authentication Error</strong></dt>
+  <dd>The sender account that you're trying to use to send a message couldn't be
+authenticated. Possible causes are: <ul>
+<li>Authorization header missing or with invalid syntax.</li>
+<li>Invalid project number sent as key.</li>
+<li>Key valid but with GCM service disabled.</li>
+<li>Request originated from a server not whitelisted in the Server Key IPs.</li>
+
+</ul>
+Check that the token you're sending inside the <code>Authorization</code> header
+is the correct API key associated with your project. You can check the validity
+of your API key by running the following command:<br/>
+
+<pre># api_key=YOUR_API_KEY
+
+# curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"ABC\"]}"</pre>
+
+
+
+If you receive a 401 HTTP status code, your API key is not valid. Otherwise you
+should see something like this:<br/>
+
+<pre>
+{"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
+</pre>
+If you want to confirm the validity of a registration ID, you can do so by
+replacing "ABC" with the registration ID.
+<br/>
+Happens when the HTTP status code is 401.
+
+  <dt id="timeout"><strong>Timeout</strong></dt>
+
+<dd>The server couldn't process the request in time. You should retry the
+same request, but you MUST obey the following requirements:
+
+<ul>
+
+<li>Honor the <code>Retry-After</code> header if it's included in the response
+from the GCM server.</li>
+
+
+<li>Implement exponential back-off in your retry mechanism. This means an
+exponentially increasing delay after each failed retry (e.g. if you waited one
+second before the first retry, wait at least two second before the next one,
+then 4 seconds and so on). If you're sending multiple messages, delay each one
+independently by an additional random amount to avoid issuing a new request for
+all messages at the same time.</li>
+
+
+Senders that cause problems risk being blacklisted.
+<br />
+Happens when the HTTP status code is between 501 and 599, or when the
+<code>error</code> field of a JSON object in the results array is <code>Unavailable</code>.
+</dd>
+
+<dt id="internal_error"><strong>Internal Server Error</strong></dt>
+
+<dd>
+The server encountered an error while trying to process the request. You
+could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
+section), but if the error persists, please report the problem in the
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
+<br />
+Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
+object in the results array is <code>InternalServerError</code>.
+</dd>
+
+<dt id="restricted_package_name"><strong>Invalid Package Name</strong></dt>
+
+<dd>
+A message was addressed to a registration ID whose package name did not match
+the value passed in the request. Happens when error code is
+<code>InvalidPackageName</code>.
+</dd>
+</dl>
+
+<h3 id="example-responses">Example responses</h3>
+<p>This section shows a few examples of responses indicating messages that were
+processed successfully. See <a href="#request">Request Format</a> for
+the requests these responses are based on.</p>
+<p> Here is a simple case of a JSON message successfully sent to one recipient
+without canonical IDs in the response:</p>
+<pre class="prettyprint pretty-json">{ "multicast_id": 108,
+  "success": 1,
+  "failure": 0,
+  "canonical_ids": 0,
+  "results": [
+    { "message_id": "1:08" }
+  ]
+}</pre>
+
+<p>Or if the request was in plain-text format:</p>
+<pre class="prettyprint">id=1:08
+</pre>
+
+<p>Here are JSON results for 6 recipients (IDs 4, 8, 15, 16, 23, and 42 respectively)
+with 3 messages successfully processed, 1 canonical registration ID returned,
+and 3 errors:</p>
+<pre class="prettyprint pretty-json">{ "multicast_id": 216,
+  "success": 3,
+  "failure": 3,
+  "canonical_ids": 1,
+  "results": [
+    { "message_id": "1:0408" },
+    { "error": "Unavailable" },
+    { "error": "InvalidRegistration" },
+    { "message_id": "1:1516" },
+    { "message_id": "1:2342", "registration_id": "32" },
+    { "error": "NotRegistered"}
+  ]
+}
+</pre>
+<p> In this example:</p>
+<ul>
+  <li>First message: success, not required.</li>
+  <li>Second message: should be resent (to registration ID 8).</li>
+  <li>Third message: had an unrecoverable error (maybe the value got corrupted
+in the database).</li>
+  <li>Fourth message: success, nothing required.</li>
+  <li>Fifth message: success, but the registration ID should be updated in the
+server database (from 23 to 32).</li>
+  <li>Sixth message: registration ID (42) should be removed from the server database
+because the application was uninstalled from the device.</li>
+</ul>
+<p>Or if just the 4th message above was sent using plain-text format:</p>
+<pre class="prettyprint">Error=InvalidRegistration
+</pre>
+<p>If the 5th message above was also sent using plain-text format:</p>
+<pre class="prettyprint">id=1:2342
+registration_id=32
+</pre>
+
+
+<h2 id="app-server">Implementing an HTTP-Based App Server</h2>
+
+<p>This section gives examples of implementing an app server that works with the
+GCM HTTP connection server. Note that a full GCM implementation requires a
+client-side implementation, in addition to the server.</a>
+
+
+<p>Requirements</p>
+<p>For the web server:</p>
+<ul>
+  <li> <a href="http://ant.apache.org/">Ant 1.8</a> (it might work with earlier versions, but it's not guaranteed).</li>
+  <li>One of the following:
+    <ul>
+      <li>A running web server compatible with Servlets API version 2.5, such as
+<a href="http://tomcat.apache.org/">Tomcat 6</a> or <a href="http://jetty.codehaus.org/">Jetty</a>, or</li>
+      <li><a href="http://code.google.com/appengine/">Java App Engine SDK</a>
+version 1.6 or later.</li>
+    </ul>
+  </li>
+  <li>A Google account registered to use GCM.</li>
+  <li>The API  key for that account.</li>
+</ul>
+<p>For the Android application:</p>
+<ul>
+  <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
+  <li>The Google API project number of the account registered to use GCM.</li>
+</ul>
+
+<h3 id="gcm-setup">Setting Up GCM</h3>
+<p>Before proceeding with the server and client setup, it's necessary to register
+a Google account with the Google API Console, enable Google Cloud Messaging in GCM,
+and obtain an API key from the <a href="https://code.google.com/apis/console">
+Google API Console</a>.</p>
+<p>For instructions on how to set up GCM, see <a href="gs.html">Getting Started</a>.</p>
+
+
+<h3 id="server-setup">Setting Up an HTTP Server</h3>
+<p>This section describes the different options for setting up an HTTP server.</p>
+
+<h4 id="webserver-setup">Using a standard web server</h4>
+<p>To set up the server using a standard, servlet-compliant web server:</p>
+<ol>
+  <li>From the <a href="http://code.google.com/p/gcm">open source site</a>,
+download the following directories: <code>gcm-server</code>,
+<code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
+
+
+  <li>In a text editor, edit the <code>samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key</code> and replace the existing text with the API key obtained above.</li>
+  <li>In a shell window, go to the <code>samples/gcm-demo-server</code> directory.</li>
+  <li>Generate the server's WAR file by running <code>ant war</code>:</li>
+
+  <pre class="prettyprint">$ ant war
+
+Buildfile:build.xml
+
+init:
+   [mkdir] Created dir: build/classes
+   [mkdir] Created dir: dist
+
+compile:
+   [javac] Compiling 6 source files to build/classes
+
+war:
+     [war] Building war: <strong>dist/gcm-demo.war</strong>
+
+BUILD SUCCESSFUL
+Total time: 0 seconds
+</pre>
+
+  <li>Deploy the <code>dist/gcm-demo.war</code> to your running server. For instance, if you're using Jetty, copy <code>gcm-demo.war</code> to the <code>webapps</code> directory of the Jetty installation.</li>
+  <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/gcm-demo/home</code>, where <code>gcm-demo</code> is the application context and <code>/home</code> is the path of the main servlet.
+
+  </li>
+</ol>
+<p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows. </p>
+
+<p> You server is now ready.</p>
+
+<h4 id="appengine-setup">Using App Engine for Java</h4>
+
+<p>To set up the server using a standard App Engine for Java:</p>
+<ol>
+  <li>Get the files from the <a href="http://code.google.com/p/gcm">open source
+site</a>, as described above.</p>
+  </li>
+  <li>In a text editor, edit
+<code>samples/gcm-demo-appengine/src/com/google/android/gcm/demo/server/ApiKeyInitializer.java</code>
+and replace the existing text with the API key obtained above.
+
+  <p class="note"><strong>Note:</strong> The API key value set in that class will
+be used just once to create a persistent entity on App Engine. If you deploy
+the application, you can use App Engine's <code>Datastore Viewer</code> to change
+it later.</p>
+
+  </li>
+  <li>In a shell window, go to the <code>samples/gcm-demo-appengine</code> directory.</li>
+  <li>Start the development App Engine server by <code>ant runserver</code>,
+using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK
+and <code>-Dserver.host</code> to set your server's hostname or IP address:</li>
+
+<pre class="prettyprint">
+$ ant -Dsdk.dir=/opt/google/appengine-java-sdk runserver -Dserver.host=192.168.1.10
+Buildfile: gcm-demo-appengine/build.xml
+
+init:
+    [mkdir] Created dir: gcm-demo-appengine/dist
+
+copyjars:
+
+compile:
+
+datanucleusenhance:
+  [enhance] DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
+  [enhance] DataNucleus Enhancer completed with success for 0 classes. Timings : input=28 ms, enhance=0 ms, total=28 ms. Consult the log for full details
+  [enhance] DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
+
+runserver:
+     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.jetty.JettyLogger info
+     [java] INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
+     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
+     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/appengine-web.xml
+     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
+     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/web.xml
+     [java] Jun 15, 2012 8:46:09 PM com.google.android.gcm.demo.server.ApiKeyInitializer contextInitialized
+     [java] SEVERE: Created fake key. Please go to App Engine admin console, change its value to your API Key (the entity type is 'Settings' and its field to be changed is 'ApiKey'), then restart the server!
+     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
+     [java] INFO: The server is running at http://192.168.1.10:8080/
+     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
+     [java] INFO: The admin console is running at http://192.168.1.10:8080/_ah/admin
+</pre>
+
+  <li>Open the server's main page in a browser. The URL depends on the server
+you're using and your machine's IP address, but it will be something like
+<code>http://192.168.1.10:8080/home</code>, where <code>/home</code>
+is the path of the main servlet.</li>
+
+  <p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code>
+on Linux or MacOS, or <code>ipconfig</code> on Windows.</p>
+
+</ol>
+<p> You server is now ready.</p>
diff --git a/docs/html/google/gcm/index.jd b/docs/html/google/gcm/index.jd
index 8f325b8..70f7a9c 100644
--- a/docs/html/google/gcm/index.jd
+++ b/docs/html/google/gcm/index.jd
@@ -1,5 +1,5 @@
 page.title=Google Cloud Messaging for Android
-page.tags="gcm"
+page.tags=gcm
 header.hide=1
 @jd:body
 
diff --git a/docs/html/google/gcm/notifications.jd b/docs/html/google/gcm/notifications.jd
index 5171850..43a7368 100644
--- a/docs/html/google/gcm/notifications.jd
+++ b/docs/html/google/gcm/notifications.jd
@@ -14,14 +14,15 @@
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#what">What are User Notifications?</a> </li>
-  <li><a href="#examples">Examples</a>
-    <ol>
-      <li><a href="#create">Generate a notification key</a></li>
-      <li><a href="#add">Add registration IDs</a></li>
-      <li><a href="#remove">Remove registration IDs</a></li>
-      <li><a href="#upstream">Send upstream messages</a></li>
-      <li><a href="#response">Response formats</a></li>
+  <li><a href="#request">Request Format</a></li>
+  <li><a href="#create">Generate a Notification Key</a></li>
+  <li><a href="#add">Add Registration IDs</a></li>
+  <li><a href="#remove">Remove Registration IDs</a></li>
+  <li><a href="#upstream">Send Upstream Messages</a></li>
+  <li><a href="#response">Response Formats</a>
+    <ol class="toc">
+      <li><a href="#response-create">Create/add/remove operations</a>
+      <li><a href="#response-send">Send operations</a>
     </ol>
   </li>
 </ol>
@@ -38,32 +39,51 @@
 
 <p class="note"><strong>Note:</strong> To try out this feature, sign up using <a href="https://services.google.com/fb/forms/gcm/">this form</a>.</p>
 
-<p>The upstream messaging (device-to-cloud) feature described in this document is part of the Google Play services platform. Upstream messaging is available through the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> APIs. To use upstream messaging and the new streamlined registration process, you must <a href="{@docRoot}google/play-services/setup.html">set up</a> the Google Play services SDK.</p>
 
-<h2 id="what">What are User Notifications?</h2>
-
-<p>Third party servers can send a single message to multiple instance of an app running on devices owned by a single user. This feature is called <em>user notifications</em>. User notifications make it possible for every app instance that a user owns to reflect the latest messaging state. For example:</p>
+<p>With user notifications, 3rd-party app servers can send a single message to
+multiple instance of an app running on devices owned by a single user. This feature
+is called <em>user notifications</em>. User notifications make it possible for every
+app instance that a user owns to reflect the latest messaging state. For example:</p>
 
   <ul>
-  <li>If a message has been handled on one device, the GCM message on the other devices are dismissed. For example, if a user has handled a calendar notification on one device, the notification will go away on the user's other devices.</li>
-  <li>If a message has not been delivered yet to a device and but it has been handled, the GCM server removes it from the unsent queue for the other devices.</li>
-  <li>Likewise, a device can send messages to the {@code notification_key}, which is the token that GCM uses to fan out notifications to all devices whose registration IDs are associated with the key.</li>
+  <li>If a message has been handled on one device, the GCM message on the other
+devices are dismissed. For example, if a user has handled a calendar notification
+on one device, the notification will go away on the user's other devices.</li>
+
+  <li>If a message has not been delivered yet to a device and but it has been handled,
+the GCM server removes it from the unsent queue for the other devices.</li>
+
+  <li>Likewise, a device can send messages to the {@code notification_key}, which
+is the token that GCM uses to fan out notifications to all devices whose
+registration IDs are associated with the key.</li>
 </ul>
 
-<p>The way this works is that during registration, the 3rd-party server requests a {@code notification_key}. The {@code notification_key} maps a particular user to all of the user's associated registration IDs (a regID represents a particular Android application running on a particular device). Then instead of sending one message to one regID at a time, the 3rd-party server can send a message to to the {@code notification_key}, which then sends the message to all of the user's regIDs.</p>
+<p>The way this works is that during registration, the 3rd-party server requests
+a {@code notification_key}. The {@code notification_key} maps a particular user
+to all of the user's associated registration IDs (a regID represents a particular
+Android application running on a particular device). Then instead of sending one
+message to one regID at a time, the 3rd-party server can send a message to to the
+{@code notification_key}, which then sends the message to all of the user's regIDs.</p>
 
-<p class="note"><strong>Note:</strong> A notification dismissal message is like any other upstream message, meaning that it will be delivered to the other devices that belong to the specified {@code notification_key}. You should design your app to handle cases where the app receives a dismissal message, but has not yet displayed the notification that is being dismissed. You can solve this by caching the dismissal and then reconciling it with the corresponding notification.
+<p class="note"><strong>Note:</strong> A notification dismissal message is like any
+other upstream message, meaning that it will be delivered to the other devices that
+belong to the specified {@code notification_key}. You should design your app to
+handle cases where the app receives a dismissal message, but has not yet displayed
+the notification that is being dismissed. You can solve this by caching the dismissal
+and then reconciling it with the corresponding notification.
 </p>
 
-<p>You can use this feature with either the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), or the older <a href="gcm.html">GCM HTTP server</a>.</p>
+<p>You can use this feature with either the <a href="ccs.html">XMPP</a> (CCS) or
+<a href="http.html">HTTP</a> connection server.</p>
 
 
-<h3 id="examples">Examples</h3>
+<p>The examples below show you how to perform generate/add/remove operations,
+and how to send upstream messages. For generate/add/remove operations, the
+message body is JSON.</p>
 
-<p>The examples in this section show you how to perform generate/add/remove operations, and how to send upstream messages. For generate/add/remove operations, the message body is JSON.</p>
-
-<h4 id="request">Request format</h4>
-<p>To send a  message, the application server issues a POST request to <code>https://android.googleapis.com/gcm/notification</code>.</p>
+<h2 id="request">Request Format</h2>
+<p>To send a  message, the application server issues a POST request to
+<code>https://android.googleapis.com/gcm/notification</code>.</p>
 
 <p>Here is the HTTP request header you should use for all create/add/remove operations:</p>
 
@@ -72,12 +92,22 @@
 Header: "Authorization", "key=API_KEY"
 </pre>
 
-<h4 id="create">Generate a notification key</h4>
+<h2 id="create">Generate a Notification Key</h2>
 
-<p>This example shows how to create a new <code>notification_key</code> for a <code>notification_key_name</code> called <code>appUser-Chris</code>. The {@code notification_key_name} is a name or identifier (can be a username for a 3rd-party app) that is unique to a given user. It is used by third parties to group together registration IDs for a single user. Note that <code>notification_key_name</code> and <code>notification_key</code> are unique to a group of registration IDs. It is also important that <code>notification_key_name</code> be uniquely named per app in case you have multiple apps for the same project ID. This ensures that notifications only go to the intended target app.</p>
+<p>This example shows how to create a new <code>notification_key</code> for a
+<code>notification_key_name</code> called <code>appUser-Chris</code>.
+The {@code notification_key_name} is a name or identifier (can be a username for
+a 3rd-party app) that is unique to a given user. It is used by third parties to
+group together registration IDs for a single user. Note that <code>notification_key_name</code>
+and <code>notification_key</code> are unique to a group of registration IDs. It is also
+important that <code>notification_key_name</code> be uniquely named per app in case
+you have multiple apps for the same project ID. This ensures that notifications
+only go to the intended target app.</p>
 
 
-<p>A create operation returns a token (<code>notification_key</code>). Third parties must save this token (as well as its mapping to the <code>notification_key_name</code>) to use in subsequent operations:</p>
+<p>A create operation returns a token (<code>notification_key</code>). Third parties
+must save this token (as well as its mapping to the <code>notification_key_name</code>)
+to use in subsequent operations:</p>
 
 <pre>request:
 { 
@@ -86,11 +116,14 @@
    &quot;registration_ids&quot;: [&quot;4&quot;, &quot;8&quot;, &quot;15&quot;, &quot;16&quot;, &quot;23&quot;, &quot;42&quot;]
 }</pre>
 
-<h4 id="add">Add registration IDs</h4>
+<h2 id="add">Add Registration IDs</h2>
 
-<p>This example shows how to add registration IDs for a given notification key. The maximum number of members allowed for a {@code notification_key} is 10.</p>
+<p>This example shows how to add registration IDs for a given notification key.
+The maximum number of members allowed for a {@code notification_key} is 10.</p>
 
-<p>Note that the <code>notification_key_name</code> is not strictly required for adding/removing regIDs. But including it protects you against accidentally using the incorrect <code>notification_key</code>.</p>
+<p>Note that the <code>notification_key_name</code> is not strictly required for
+adding/removing regIDs. But including it protects you against accidentally using
+the incorrect <code>notification_key</code>.</p>
 
 <pre>request:
 { 
@@ -100,7 +133,7 @@
    &quot;registration_ids&quot;: [&quot;4&quot;, &quot;8&quot;, &quot;15&quot;, &quot;16&quot;, &quot;23&quot;, &quot;42&quot;]
 }</pre>
 
-<h4 id="remove">Remove registration IDs</h4>
+<h2 id="remove">Remove Registration IDs</h2>
 
 <p>This example shows how to remove registration IDs for a given notification key:</p>
 <pre>request:
@@ -111,9 +144,14 @@
    &quot;registration_ids&quot;: [&quot;4&quot;, &quot;8&quot;, &quot;15&quot;, &quot;16&quot;, &quot;23&quot;, &quot;42&quot;]
 }</pre>
 
-<h4 id="upstream">Send upstream messages</h4>
+<h2 id="upstream">Send Upstream Messages</h2>
 
-<p>To send an upstream (device-to-cloud) message, you must use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> API. Specifying a {@code notification_key} as the target for an upstream message allows a user on one device to send a message to other devices in the notification group&mdash;for example, to dismiss a notification. Here is an example that shows targeting a {@code notification_key}:</p>
+<p>To send an upstream (device-to-cloud) message, you must use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> API. Specifying a {@code notification_key} as the target
+for an upstream message allows a user on one device to send a message to other
+devices in the notification group&mdash;for example, to dismiss a notification.
+Here is an example that shows targeting a {@code notification_key}:</p>
 
 <pre>GoogleCloudMessaging gcm = GoogleCloudMessaging.get(context);
 String to = NOTIFICATION_KEY;
@@ -125,17 +163,21 @@
 gcm.send(to, id, data);
 </pre>
 
-<p>This call generates the necessary XMPP stanza for sending the message. The Bundle data consists of a key-value pair.</p>
+<p>This call generates the necessary XMPP stanza for sending the message. The
+Bundle data consists of a key-value pair.</p>
 
-<p>For a complete example, see <a href="gs.html#gs_example">Getting Started</a>. 
+<p>For a complete example, see <a href="client.html">Implementing GCM Client</a>.
 
-<h4 id="response">Response formats</h4>
+<h2 id="response">Response Formats</h2>
 
-<p>This section shows examples of the responses that can be returned for notification key operations.</p>
+<p>This section shows examples of the responses that can be returned for
+notification key operations.</p>
 
-<h5>Response for create/add/remove operations</h5>
+<h3 id="response-create">Create/add/remove operations</h3>
 
-<p>When you make a request to create a {@code notification_key} or to add/remove its the wayregIDs, a successful response always returns the <code>notification_key</code>. This is the {@code notification_key} you will use for sending messages:</p>
+<p>When you make a request to create a {@code notification_key} or to add/remove its
+regIDs, a successful response always returns the <code>notification_key</code>.
+his is the {@code notification_key} you will use for sending messages:</p>
 
 <pre>HTTP status: 200
 { 
@@ -143,18 +185,23 @@
 }</pre>
 
 
-<h5>Response for send operations</h5>
+<h3 id="response-send">Send operations</h3>
 
-<p>For a send operation that has a {@code notification_key} as its target, the possible responses are success, partial success, and failure.</p>
+<p>For a send operation that has a {@code notification_key} as its target, the
+possible responses are success, partial success, and failure.</p>
 
-<p>Here is an example of "success"&mdash;the {@code notification_key} has 2 regIDs associated with it, and the message was successfully sent to both of them:</p>
+<p>Here is an example of "success"&mdash;the {@code notification_key} has 2 regIDs
+associated with it, and the message was successfully sent to both of them:</p>
 
 <pre>{
   "success": 2,
   "failure": 0
 }</pre>
 
-<p>Here is an example of "partial success"&mdash;the {@code notification_key} has 3 regIDs associated with it. The message was successfully send to 1 of the regIDs, but not to the other 2. The response message lists the regIDs that failed to receive the message:</p>
+<p>Here is an example of "partial success"&mdash;the {@code notification_key} has
+3 regIDs associated with it. The message was successfully send to 1 of the regIDs,
+but not to the other 2. The response message lists the regIDs that failed to
+receive the message:</p>
 
 <pre>{
   "success":1,
@@ -165,7 +212,9 @@
   ]
 }</pre>
 
-<p>In the case of failure, the response has HTTP code 503 and no JSON. When a message fails to be delivered to one or more of the regIDs associated with a {@code notification_key}, the 3rd-party server should retry.</p>
+<p>In the case of failure, the response has HTTP code 503 and no JSON. When a message
+fails to be delivered to one or more of the regIDs associated with a {@code notification_key},
+the 3rd-party server should retry.</p>
 
 
 
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
index 92a1531..b5e6b48 100644
--- a/docs/html/google/gcm/server.jd
+++ b/docs/html/google/gcm/server.jd
@@ -1,36 +1,34 @@
-page.title=GCM Server
+page.title=Implementing GCM Server
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Quickview</h2>
-
-<ul>
-<li>Understand how to set up the server side of a GCM app.</li>
-<li>Become familiar with the <a href="{@docRoot}reference/com/google/android/gcm/server/package-summary.html">GCM server helper library</a>.</li>
-</ul>
-
-
 <h2>In this document</h2>
 
-<ol>
-  <li><a href="#requirements">Requirements</a> </li>
-  <li><a href="#gcm-setup">Setting Up GCM</a></li>
-  <li><a href="#server-setup">Setting Up an HTTP Server</a>
-    <ol>
-      <li><a href="#webserver-setup">Using a standard web server</a></li>
-      <li><a href="#appengine-setup">Using App Engine for Java</a></li>
+<ol class="toc">
+  <li><a href="#choose">Choosing a GCM Connection Server</a></li>
+  <li><a href="#role">Role of the 3rd-party Application Server</a></li>
+    <li><a href="#send-msg">Sending Messages</a>
+    <ol class="toc">
+
+      <li><a href="#target">Target</a></li>
+      <li><a href="#payload">Payload</a></li>
+      <li><a href="#params">Message parameters</a>
     </ol>
+    </li>
+  <li><a href="#receive">Receiving Messages</a> </li>
   </li>
+
 </ol>
 
 <h2>See Also</h2>
 
 <ol class="toc">
 <li><a href="gs.html">Getting Started</a></li>
-<li><a href="client.html">GCM Client</a></li>
-<li><a href="ccs.html">Cloud Connection Server</a></li>
+<li><a href="client.html">Implementing GCM Client</a></li>
+<li><a href="ccs.html">Cloud Connection Server (XMPP)</a></li>
+<li><a href="http.html">HTTP Connection Server</a></li>
 
 
 </ol>
@@ -39,122 +37,342 @@
 </div>
 
 
-
-
-<p>This document gives examples of GCM server-side code for HTTP. For an example of an XMPP server (<a href="ccs.html">Cloud Connection Server</a>), see <a href="gs.html#server">Getting Started</a>. Note that a full GCM implementation requires a client-side implementation, in addition to the server. For a complete working example that includes client and server-side code, see <a href="gs.html">Getting Started</a>.</a>
-
-<h2 id="requirements">Requirements</h2>
-<p>For the web server:</p>
+<p>The server side of GCM consists of 2 components:</p>
 <ul>
-  <li> <a href="http://ant.apache.org/">Ant 1.8</a> (it might work with earlier versions, but it's not guaranteed).</li>
-  <li>One of the following:
-    <ul>
-      <li>A running web server compatible with Servlets API version 2.5, such as <a href="http://tomcat.apache.org/">Tomcat 6</a> or <a href="http://jetty.codehaus.org/">Jetty</a>, or</li>
-      <li><a href="http://code.google.com/appengine/">Java App Engine SDK</a> version 1.6 or later.</li>
+<li>Google-provided <strong>GCM Connection Servers</strong>
+take messages from a 3rd-party application server and send them to a GCM-enabled
+Android application (the &quot;client app&quot;) running on a device. For example,
+Google provides connection servers for <a href="{@docRoot}google/gcm/http.html">
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP).</li>
+<li>A <strong>3rd-party application server</strong> that you must implement. This application
+server sends data to a GCM-enabled Android application via the chosen GCM connection server.</li>
+</ul>
+</p>
+
+<p>Here are the basic steps you follow to implement your 3rd-party app server:</p>
+
+<ul>
+      <li>Decide which GCM connection server(s) you want to use. Note that if you want to use
+      upstream messaging from your client applications, you must use CCS. For a more detailed
+      discussion of this, see <a href="#choose">
+      Choosing a GCM Connection Server</a>.</li>
+      <li>Decide how you want to implement your app server. For example:
+        <ul>
+          <li>If you decide to use the HTTP connection server, you can use the
+GCM server helper library and demo app to help in implementing your app server.</li>
+          <li>If you decide to use the XMPP connection server, you can use
+the provided Python or Java <a href="http://www.igniterealtime.org/projects/smack/">
+Smack</a> demo apps as a starting point.</li>
+        <li>Note that Google AppEngine does not support connections to CCS.</li>
+        </ul>
+      </li>
     </ul>
   </li>
-  <li>A Google account registered to use GCM.</li>
-  <li>The API  key for that account.</li>
 </ul>
-<p>For the Android application:</p>
+
+<p>A full GCM implementation requires both a client implementation and a server
+implementation. For more
+information about implementing the client side, see <a href="client.html">
+Implementing GCM Client</a>.</p>
+
+<h2 id="choose">Choosing a GCM Connection Server</h2>
+
+<p>Currently GCM provides two connection servers: <a href="{@docRoot}google/gcm/http.html">
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP). You can use them
+separately or in tandem. CCS messaging differs from GCM HTTP messaging in the following ways:</p>
 <ul>
-  <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
-  <li>The Google API project number of the account registered to use GCM.</li>
+  <li>Upstream/Downstream messages
+    <ul>
+      <li>GCM HTTP: Downstream only: cloud-to-device. </li>
+      <li>CCS: Upstream and downstream (device-to-cloud, cloud-to-device). </li>
+    </ul>
+  </li>
+  <li>Asynchronous messaging
+    <ul>
+      <li>GCM HTTP: 3rd-party app servers send messages as HTTP POST requests and
+wait for a response. This mechanism is synchronous and causes the sender to block
+before sending another message.</li>
+      <li>CCS: 3rd-party app servers connect to Google infrastructure using a
+persistent XMPP connection and send/receive messages to/from all their devices
+at full line speed. CCS sends acknowledgment or failure notifications (in the
+form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
+    </ul>
+  </li>
+
+  <li>JSON
+    <ul>
+      <li>GCM HTTP: JSON messages sent as HTTP POST.</li>
+      <li>CCS: JSON messages encapsulated in XMPP messages.</li>
+    </ul>
+  </li>
 </ul>
-<h2 id="gcm-setup">Setting Up GCM</h2>
-<p>Before proceeding with the server and client setup, it's necessary to register a Google account with the Google API Console, enable Google Cloud Messaging in GCM, and obtain an API key from the <a href="https://code.google.com/apis/console">Google API Console</a>.</p>
-<p>For instructions on how to set up GCM, see <a href="gs.html">Getting Started</a>.</p>
 
+<h2 id="role">Role of the 3rd-party Application Server</h2>
 
-<h2 id="server-setup">Setting Up an HTTP Server</h2>
-<p>This section describes the different options for setting up an HTTP server.</p>
-<h3 id="webserver-setup">Using a standard web server</h3>
-<p>To set up the server using a standard, servlet-compliant web server:</p>
+<p>Before you can write client Android applications that use the GCM feature, you must
+have an  application server that meets the following criteria:</p>
+
+<ul>
+  <li>Able to communicate with your client.</li>
+  <li>Able to  fire off properly formatted requests to the GCM server.</li>
+  <li>Able to handle requests and resend them as needed, using
+<a href="http://en.wikipedia.org/wiki/Exponential_backoff">exponential back-off.</a></li>
+  <li>Able to store the API key and client registration IDs. The
+API key is included in the header of POST requests that send
+messages.</li>
+ <li>Able to store the API key and client registration IDs.</li>
+ <li>Able to generate message IDs to uniquely identify each message it sends.</li>
+</ul>
+
+<h2 id="send-msg">Sending Messages</h2>
+
+<p>Here is the general sequence of events that occurs when a 3rd-party application
+server sends a message:</p>
 <ol>
-  <li>From the <a href="http://code.google.com/p/gcm">open source site</a>, download the following directories: <code>gcm-server</code>, <code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
-
-
-  <li>In a text editor, edit the <code>samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key</code> and replace the existing text with the API key obtained above.</li>
-  <li>In a shell window, go to the <code>samples/gcm-demo-server</code> directory.</li>
-  <li>Generate the server's WAR file by running <code>ant war</code>:</li>
-  
-  <pre class="prettyprint">$ ant war
-
-Buildfile:build.xml
-
-init:
-   [mkdir] Created dir: build/classes
-   [mkdir] Created dir: dist
-
-compile:
-   [javac] Compiling 6 source files to build/classes
-
-war:
-     [war] Building war: <strong>dist/gcm-demo.war</strong>
-
-BUILD SUCCESSFUL
-Total time: 0 seconds
-</pre>
-  
-  <li>Deploy the <code>dist/gcm-demo.war</code> to your running server. For instance, if you're using Jetty, copy <code>gcm-demo.war</code> to the <code>webapps</code> directory of the Jetty installation.</li>
-  <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/gcm-demo/home</code>, where <code>gcm-demo</code> is the application context and <code>/home</code> is the path of the main servlet.
-    
-  </li>
+  <li>The application server sends a message to GCM servers.</li>
+  <li>Google enqueues and stores the message in case the device is offline.</li>
+  <li>When the device is online, Google sends the message to the device.</li>
+  <li>On the device, the system broadcasts the message to the specified Android
+application via Intent broadcast with proper permissions, so that only the targeted
+ndroid application gets the message. This wakes the Android application up.
+The Android application does not need to be running beforehand to receive the message.</li>
+  <li>The Android application processes the message. </li>
 </ol>
-<p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows. </p>
 
-<p> You server is now ready.</p>
+<p>The following sections describe the basic requirements for
+sending messages.</p>
 
-<h3 id="appengine-setup">Using App Engine for Java</h3>
+<h3 id="target">Target</h3>
+<p>Required. When your app server sends a message in GCM, it must specify a target.</p>
+<p>For HTTP you must specify the target as one of:</p>
+<ul>
+<li><code>registration_ids</code>: For sending to 1 more more devices (up to 1000).
+When you send a message to multiple registration IDs, that is called a multicast message.</li>
+<li><code>notification_key</code>: For sending to multiple devices owned by a single user.</li>
+</ul>
+<p>For CCS (XMPP):</p>
+<ul>
+<li>You must specify the target as the &quot;to&quot; field, where the &quot;to&quot;
+field may contain a single registration ID or a notification key.
+CCS does not support multicast messaging.</li>
+</ul>
+<h3 id="payload">Payload</h3>
+<p>Optional. If you are including a payload in the message, you use the <code>data</code>
+parameter to include the payload. This applies for both HTTP and CCS.</p>
 
-<p>To set up the server using a standard App Engine for Java:</p>
+<h3 id="params">Message parameters</h3>
+
+<p>The following table lists the parameters that a 3rd-party app server might
+include in the JSON messages it sends to a connection server. See the "Where Supported"
+column for information about which connection servers support that particular
+parameter.</p>
+
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> Message parameters.</p>
+
+<table>
+  <tr>
+    <th>Field</th>
+    <th>Description</th>
+<th>Where Supported</th>
+</tr>
+  <td><code>to</code></td>
+<td>In CCS, used in place of <code>registration_ids</code> to specify the
+recipient of a message. Its value must be a registration ID.
+The value is a string. Required.</td>
+<td>CCS</td>
+</tr>
+<tr>
+<td><code>message_id</code></td>
+<td>In CCS, uniquely identifies a message in an XMPP connection. The value is a
+string that uniquely identifies the associated message. The value is a string. Required.</td>
+<td>CCS</td>
+</tr>
+<tr>
+<td><code>message_type</code></td>
+<td>In CCS, indicates a special status message, typically sent by the system.
+However, your app server also uses this parameter to send an 'ack' or 'nack'
+message back to the CCS connection server. For more discussion of this topic, see
+<a href="ccs.html">Cloud Connection Server</a>. The value is a string. Optional.</td>
+<td>CCS</td>
+<tr>
+  <td><code>registration_ids</code></td>
+  <td>A string array with the list of devices (registration IDs) receiving the
+message. It must contain at least 1 and at most 1000 registration IDs. To send a
+multicast message, you must use JSON. For sending a single message to a single
+device, you could use a JSON object with just 1 registration id, or plain text
+(see below). A request must include a recipient&mdash;this can be either a
+registration ID, an array of registration IDs, or a {@code notification_key}.
+Required.</td>
+<td>HTTP</td>
+</tr>
+ <tr>
+    <td><code>notification_key</code></td>
+    <td>A string that maps a single user to multiple registration IDs associated
+with that user. This allows a 3rd-party server to send a single message to
+multiple app instances (typically on multiple devices) owned by a single user.
+A 3rd-party server can use {@code notification_key} as the target for a message
+instead of an individual registration ID (or array of registration IDs). The maximum
+number of members allowed for a {@code notification_key} is 10. For more discussion
+of this topic, see <a href="notifications.html">User Notifications</a>. Optional.
+</td>
+<td style="width:100px">HTTP. This feature is supported in CCS, but you use it by
+specifying a notification key in the &quot;to&quot; field.</td>
+</tr>
+  <tr>
+    <td><code>collapse_key</code></td>
+    <td>An arbitrary string (such as &quot;Updates Available&quot;) that is used
+to collapse a group of like messages
+when the device is offline, so that only the last message gets sent to the
+client. This is intended to avoid sending too many messages to the phone when it
+comes back online. Note that since there is no guarantee of the order in which
+messages get sent, the &quot;last&quot; message may not actually be the last
+message sent by the application server. Collapse keys are also called
+<a href="#s2s">send-to-sync messages</a>.
+<br>
+<strong>Note:</strong> GCM allows a maximum of 4 different collapse keys to be
+used by the GCM server
+at any given time. In other words, the GCM server can simultaneously store 4
+different send-to-sync messages per device, each with a different collapse key.
+If you exceed
+this number GCM will only keep 4 collapse keys, with no guarantees about which
+ones they will be. See <a href="adv.html#collapsible">Advanced Topics</a> for more
+discussion of this topic. Optional.</td>
+<td>CCS, HTTP</td>
+</tr>
+  <tr>
+    <td><code>data</code></td>
+    <td>A JSON object whose fields represents the key-value pairs of the message's
+payload data. If present, the payload data it will be
+included in the Intent as application data, with the key being the extra's name.
+For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra
+named <code>score</code> whose value is the string <code>3x1</code>.
+There is no limit on the number of key/value pairs, though there is a limit on
+the total size of the message (4kb). The values could be any JSON object, but we
+recommend using strings, since the values will be converted to strings in the GCM
+server anyway. If you want to include objects or other non-string data types
+(such as integers or booleans), you have to do the conversion to string yourself.
+Also note that the key cannot be a reserved word (<code>from</code> or any word
+starting with <code>google.</code>). To complicate things slightly, there are
+some reserved words (such as <code>collapse_key</code>) that are technically
+allowed in payload data. However, if the request also contains the word, the
+value in the request will overwrite the value in the payload data. Hence using
+words that are defined as field names in this table is not recommended, even in
+cases where they are technically allowed. Optional.</td>
+<td>CCS, HTTP</td>
+</tr>
+  <tr>
+    <td><code>delay_while_idle</code></td>
+    <td>If included, indicates that the message should not be sent immediately
+if the device is idle. The server will wait for the device to become active, and
+then only the last message for each <code>collapse_key</code> value will be
+sent. The default value is <code>false</code>, and must be a JSON boolean. Optional.</td>
+<td>CCS, HTTP</td>
+</tr>
+  <tr>
+    <td><code>time_to_live</code></td>
+    <td>How long (in seconds) the message should be kept on GCM storage if the
+device is offline. Optional (default time-to-live is 4 weeks, and must be set as
+a JSON number).</td>
+<td>CCS, HTTP</td>
+</tr>
+<tr>
+  <td><code>restricted_package_name</code></td>
+  <td>A string containing the package name of your application. When set, messages
+will only be sent to registration IDs that match the package name. Optional.
+  </td>
+<td>HTTP</td>
+</tr>
+<tr>
+  <td><code>dry_run</code></td>
+  <td>If included, allows developers to test their request without actually
+sending a message. Optional. The default value is <code>false</code>, and must
+be a JSON boolean.
+  </td>
+<td>HTTP</td>
+</tr>
+</table>
+
+<p>If you want to test your request (either JSON or plain text) without delivering
+the message to the devices, you can set an optional HTTP or JSON parameter called
+<code>dry_run</code> with the value <code>true</code>. The result will be almost
+identical to running the request without this parameter, except that the message
+will not be delivered to the devices. Consequently, the response will contain fake
+IDs for the message and multicast fields.</p>
+
+<h3 id="plain-text">Plain text (HTTP only)</h3>
+
+<p>If you are using plain text instead of JSON, the message fields must be set as
+HTTP parameters sent in the body, and their syntax is slightly different, as
+described below:
+<table>
+  <tr>
+    <th>Field</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>registration_id</code></td>
+    <td>Must contain the registration ID of the single device receiving the message.
+Required.</td>
+  </tr>
+  <tr>
+    <td><code>collapse_key</code></td>
+    <td>Same as JSON (see previous table). Optional.</td>
+  </tr>
+  <tr>
+    <td><code>data.&lt;key&gt;</code></td>
+
+    <td>Payload data, expressed as parameters prefixed with <code>data.</code> and
+suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would
+result in an intent extra named <code>score</code> whose value is the string
+<code>3x1</code>. There is no limit on the number of key/value parameters, though
+there is a limit on the total size of the  message. Also note that the key cannot
+be a reserved word (<code>from</code> or any word starting with
+<code>google.</code>). To complicate things slightly, there are some reserved words
+(such as <code>collapse_key</code>) that are technically allowed in payload data.
+However, if the request also contains the word, the value in the request will
+overwrite the value in the payload data. Hence using words that are defined as
+field names in this table is not recommended, even in cases where they are
+technically allowed. Optional.</td>
+
+  </tr>
+  <tr>
+    <td><code>delay_while_idle</code></td>
+    <td>Should be represented as <code>1</code> or <code>true</code> for
+<code>true</code>, anything else for <code>false</code>. Optional. The default
+value is <code>false</code>.</td>
+  </tr>
+  <tr>
+    <td><code>time_to_live</code></td>
+    <td>Same as JSON (see previous table). Optional.</td>
+  </tr>
+<tr>
+  <td><code>restricted_package_name</code></td>
+  <td>Same as JSON (see previous table). Optional.
+  </td>
+</tr>
+<tr>
+  <td><code>dry_run</code></td>
+  <td>Same as JSON (see previous table). Optional.
+  </td>
+</tr>
+</table>
+
+<h2 id="receive">Receiving Messages</h2>
+
+<p>This is the sequence of events that occurs when an Android application
+installed on a mobile device receives a message:</p>
+
 <ol>
-  <li>Get the files from the <a href="http://code.google.com/p/gcm">open source site</a>, as described above.</p>
-  </li>
-  <li>In a text editor, edit <code>samples/gcm-demo-appengine/src/com/google/android/gcm/demo/server/ApiKeyInitializer.java</code> and replace the existing text with the API key obtained above.
-
-  <p class="note"><strong>Note:</strong> The API key value set in that class will be used just once to create a persistent entity on App Engine. If you deploy the application, you can use App Engine's <code>Datastore Viewer</code> to change it later.</p>
-  
-  </li>
-  <li>In a shell window, go to the <code>samples/gcm-demo-appengine</code> directory.</li>
-  <li>Start the development App Engine server by <code>ant runserver</code>, using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK and <code>-Dserver.host</code> to set your server's hostname or IP address:</li>
-
-<pre class="prettyprint">
-$ ant -Dsdk.dir=/opt/google/appengine-java-sdk runserver -Dserver.host=192.168.1.10
-Buildfile: gcm-demo-appengine/build.xml
-
-init:
-    [mkdir] Created dir: gcm-demo-appengine/dist
-
-copyjars:
-
-compile:
-
-datanucleusenhance:
-  [enhance] DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
-  [enhance] DataNucleus Enhancer completed with success for 0 classes. Timings : input=28 ms, enhance=0 ms, total=28 ms. Consult the log for full details
-  [enhance] DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
-
-runserver:
-     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.jetty.JettyLogger info
-     [java] INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
-     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
-     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/appengine-web.xml
-     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
-     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/web.xml
-     [java] Jun 15, 2012 8:46:09 PM com.google.android.gcm.demo.server.ApiKeyInitializer contextInitialized
-     [java] SEVERE: Created fake key. Please go to App Engine admin console, change its value to your API Key (the entity type is 'Settings' and its field to be changed is 'ApiKey'), then restart the server!
-     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
-     [java] INFO: The server is running at http://192.168.1.10:8080/
-     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
-     [java] INFO: The admin console is running at http://192.168.1.10:8080/_ah/admin
-</pre>
-
-  <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/home</code>, where <code>/home</code> is the path of the main servlet.</li>
-  
-  <p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows.</p>
-  
+  <li>The system receives the incoming message and extracts the raw key/value
+pairs from the message payload, if any.</li>
+  <li>The system passes the key/value pairs to the targeted Android application
+in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
+extras.</li>
+  <li>The Android application extracts the raw data
+from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
+by key and processes the data.</li>
 </ol>
-<p> You server is now ready.</p>
 
-
+<p>See the documentation for each connection server for more detail on how it
+handles responses.</p>
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 77042d3..2ded286 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -133,29 +133,32 @@
 
 
 
-  <li class="nav-section">
+   <li class="nav-section">
       <div class="nav-section-header"><a href="<?cs var:toroot ?>google/gcm/index.html">
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="<?cs var:toroot?>google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="<?cs var:toroot?>google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="<?cs var:toroot?>google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="<?cs var:toroot?>google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="<?cs var:toroot?>google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="<?cs var:toroot?>google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="<?cs var:toroot?>google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="<?cs var:toroot?>google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="<?cs var:toroot?>google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="<?cs var:toroot?>google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="<?cs var:toroot?>google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="<?cs var:toroot?>google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/google/play-services/ads.jd b/docs/html/google/play-services/ads.jd
index c666ce9..7536cb0 100644
--- a/docs/html/google/play-services/ads.jd
+++ b/docs/html/google/play-services/ads.jd
@@ -1,5 +1,5 @@
 page.title=Google Mobile Ads
-page.tags="Ads","monetization", "AdMob", "Google Play services"
+page.tags=Ads,monetization,AdMob,Google Play services
 header.hide=1
 
 @jd:body
@@ -82,4 +82,4 @@
     <p class="note"><strong>Note</strong>: The SDK doesn’t currently support DFP, Ad Exchange or Search
     Ads for Mobile Apps but support is coming soon.</p>
   </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/google/play-services/auth.jd b/docs/html/google/play-services/auth.jd
index 7acaf1c..dded599 100644
--- a/docs/html/google/play-services/auth.jd
+++ b/docs/html/google/play-services/auth.jd
@@ -1,5 +1,5 @@
 page.title=Authorization
-page.tags="AccountManager","oauth2"
+page.tags=AccountManager,oauth2
 @jd:body
 
 <div id="qv-wrapper">
@@ -236,4 +236,4 @@
     case, obtain a new token using <a
 href="{@docRoot}reference/com/google/android/gms/auth/GoogleAuthUtil.html#getToken(android.content.Context, java.lang.String, java.lang.String)"
 >{@code GoogleAuthUtil.getToken()}</a>.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/google/play-services/id.jd b/docs/html/google/play-services/id.jd
index 664c6e6..bd302c0 100644
--- a/docs/html/google/play-services/id.jd
+++ b/docs/html/google/play-services/id.jd
@@ -1,5 +1,5 @@
 page.title=Advertising ID
-page.tags="Ads","Advertising ID", "ID"
+page.tags=Ads,Advertising ID,ID
 header.hide=1
 
 @jd:body
@@ -195,4 +195,4 @@
   }
   final String id = adInfo.getId();
   final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
-}</pre>
\ No newline at end of file
+}</pre>
diff --git a/docs/html/google/play-services/location.jd b/docs/html/google/play-services/location.jd
index 1cdd247..3fbf00e 100644
--- a/docs/html/google/play-services/location.jd
+++ b/docs/html/google/play-services/location.jd
@@ -1,5 +1,5 @@
 page.title=Location APIs
-page.tags="location","geofence", "geofencing", "gps"
+page.tags=location,geofence,geofencing,gps
 header.hide=1
 @jd:body
 
diff --git a/docs/html/google/play-services/maps.jd b/docs/html/google/play-services/maps.jd
index 965444a..246664e 100644
--- a/docs/html/google/play-services/maps.jd
+++ b/docs/html/google/play-services/maps.jd
@@ -1,5 +1,5 @@
 page.title=Google Maps Android API
-page.tags="mapview","location"
+page.tags=mapview,location
 header.hide=1
 
 @jd:body
@@ -88,4 +88,4 @@
     </p>
   </div>
 
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/google/play-services/plus.jd b/docs/html/google/play-services/plus.jd
index e126dad..00b0488 100644
--- a/docs/html/google/play-services/plus.jd
+++ b/docs/html/google/play-services/plus.jd
@@ -1,5 +1,5 @@
 page.title=Google+ Platform for Android
-page.tags="authentication","signin","social"
+page.tags=authentication,signin,social
 header.hide=1
 
 @jd:body
@@ -87,4 +87,4 @@
     Google+ developer documents at <a class="external-link"
     href="https://developers.google.com/+/mobile/android/">developers.google.com/+</a>.</p>
   </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 6553c18..5c8c63b 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -1,6 +1,24 @@
 page.title=Set Up Google Play Services SDK
 @jd:body
 
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#Install">Install the Google Play Services SDK</a></li>
+  <li><a href="#Setup">Set Up a Project that Uses Google Play Services</a></li>
+  <li><a href="#Proguard">Create a Proguard Exception</a></li>
+  <li><a href="#ensure">Ensure Devices Have the Google Play services APK</a></li>
+</ol>
+
+
+</div>
+</div>
+
+
     
 <p>To develop an app using the <a href="{@docRoot}reference/gms-packages.html">Google
 Play services APIs</a>, you must download the Google Play services SDK
@@ -10,7 +28,7 @@
 <p>To test your app when using the Google Play services SDK, you must use either:</p>
 <ul>
   <li>A compatible Android
-    device that runs Android 2.2 or higher and includes Google Play Store.</li>
+    device that runs Android 2.3 or higher and includes Google Play Store.</li>
   <li>The Android emulator with an <a href="{@docRoot}tools/devices/index.html">AVD</a>
   that runs the Google APIs platform based on Android 4.2.2 or higher.</li>
 </ul>
@@ -24,9 +42,12 @@
 <p>To install the Google Play services SDK for development:</p>
 
 <ol>
-  <li>Launch the SDK Manager.
+  <li>Launch the SDK Manager in one of the following ways:
    <ul>
-    <li>From Eclipse (with <a href="{@docRoot}tools/help/adt.html">ADT</a>),
+    <li>In Android Studio, click <strong>SDK Manager</strong>
+<img src="{@docRoot}images/tools/sdk-manager-studio.png" style="vertical-align:bottom;margin:0;height:19px" />
+in the toolbar.</li>
+    <li>In Eclipse (with <a href="{@docRoot}tools/help/adt.html">ADT</a>),
     select <strong>Window</strong> &gt; <strong>Android SDK Manager</strong>.</li>
     <li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
   SDK directory.</li>
@@ -36,19 +57,25 @@
   </li>
   <li>Install the Google Play services SDK.
     <p>Scroll to the bottom of the package list, expand <b>Extras</b>, select
-    <b>Google Play services</b>, and install it.</p>
+    <b>Google Play services</b>, and install it. If you're using Android Studio, also install
+    <b>Google Repository</b> (it provides the Maven repository used for Gradle builds).</p>
       <p>The Google Play services SDK is saved in your Android SDK environment at
       <code>&lt;android-sdk&gt;/extras/google/google_play_services/</code>.</p>
+
+<p class="note"><strong>Note:</strong> Google Play services 4.0.30 (released
+November 2013) and newer versions require Android 2.3 or higher. If your app supports Android 2.2,
+you can continue development with the Google Play services SDK, but must instead install
+<b>Google Play services for Froyo</b> from the SDK Manager.</p>
+
   </li>
   <li>Install a compatible version of the Google APIs platform.
     <p>If you want to test your app on the emulator, expand the directory for <b>Android 4.2.2
     (API 17)</b> or a higher version, select <b>Google APIs</b>, and install it. Then create a
     new <a href="{@docRoot}tools/devices/index.html">AVD</a> with Google APIs as
     the platform target.</p>
-    <p class="note"><strong>Note:</strong> Only Android 4.2.2 and higher versions of the
-    Google APIs platform include Google Play services.</p>
   </li>
   <li>Make a copy of the Google Play services library project.
+    <p class="note"><strong>Note:</strong> If you are using Android Studio, skip this step.</p>
     <p>Copy the library project at
   <code>&lt;android-sdk&gt;/extras/google/google_play_services/libproject/google-play-services_lib/</code>        
   to the location where you maintain your Android app projects.
@@ -60,23 +87,77 @@
 
 
 
-<h2 id="Setup">Set Up a Project with the Library</h2>
+<h2 id="Setup">Set Up a Project that Uses Google Play Services</h2>
 
-<p>To set up a project to use the Google Play services SDK:</p>
+<p><b>Using Android Studio:</b></p>
 
 <ol>
-  <li>Reference the library project in your Android project.
-      <p>See the 
-      <a href="{@docRoot}tools/projects/projects-eclipse.html#ReferencingLibraryProject">Referencing a Library Project for Eclipse</a>
-      or <a href="{@docRoot}tools/projects/projects-cmdline.html#ReferencingLibraryProject">Referencing a Library Project on the Command Line</a>
-      for more information on how to do this.</p>
-      <p class="note"><strong>Note:</strong>
-      You should be referencing a copy of the library that you copied to your development
-      workspace&mdash;you should not reference the library directly from the Android SDK directory.</p>
+  <li>Open the <code>build.gradle</code> file inside your application directory.</li>
+  <li>Add a new build rule under <code>dependencies</code> for the latest version of
+<code>play-services</code>. For example:
+<pre class="no-pretty-print">
+apply plugin: 'android'
+...
+
+dependencies {
+    compile 'com.android.support:appcompat-v7:+'
+    <strong>compile 'com.google.android.gms:play-services:4.0.30'</strong>
+}
+</pre>
+<p>Be sure you update this version number each time Google Play services is updated.</p>
   </li>
-  <li>If you are using <a href="{@docRoot}tools/help/proguard.html">ProGuard</a>, add the following
-      lines in the <code>&lt;project_directory&gt;/proguard-project.txt</code> file
-      to prevent ProGuard from stripping away required classes:
+  <li>Save the changes and click <strong>Sync Project with Gradle Files</strong>
+<img src="{@docRoot}images/tools/sync-project.png" style="vertical-align:bottom;margin:0;height:19px" />
+in the toolbar.
+  </li>
+  <li>Open your app's manifest file and add the following tag as a child of the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a>
+element:
+<pre>
+&lt;meta-data android:name="com.google.android.gms.version"
+           android:value="&#64;integer/google_play_services_version" />
+</pre>
+  </li>
+</ol>
+
+<p>You can now begin developing features with the
+<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
+
+
+<p><b>Using Eclipse or another IDE:</b></p>
+
+<p>To make the Google Play services APIs available to your app, you must reference the library
+project you created in step 4 of the <a href="#Install">installation instructions</a>.</p>
+<p>See the <a href="{@docRoot}tools/projects/projects-eclipse.html#ReferencingLibraryProject"
+>Referencing a Library Project for Eclipse</a> or <a
+href="{@docRoot}tools/projects/projects-cmdline.html#ReferencingLibraryProject">Referencing a
+Library Project on the Command Line</a> for more information on how to do this.</p>
+
+<p class="note"><strong>Note:</strong>
+You should be referencing a copy of the library that you copied to your development
+workspace&mdash;you should not reference the library directly from the Android SDK directory.</p>
+
+<p>After you've added the Google Play services library as a dependency for your app project,
+open your app's manifest file and add the following tag as a child of the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a>
+element:
+<pre>
+&lt;meta-data android:name="com.google.android.gms.version"
+           android:value="&#64;integer/google_play_services_version" />
+</pre>
+
+
+<p>Once you've set up your project to reference the library project,
+you can begin developing features with the
+<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
+
+
+
+<h2 id="Proguard">Create a Proguard Exception</h2>
+
+<p>To prevent <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> from stripping away
+required classes, add the following lines in the
+<code>&lt;project_directory&gt;/proguard-project.txt</code> file:
 <pre>
 -keep class * extends java.util.ListResourceBundle {
     protected Object[][] getContents();
@@ -95,11 +176,13 @@
     public static final ** CREATOR;
 }
 </pre>
+
+<p class="note"><strong>Note:</strong> When using Android Studio, you must add Proguard
+to your <code>gradle.build</code> file's build types. For more information, see the
+<a href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Running-ProGuard"
+>Gradle Plugin User Guide</a>.
 </ol>
 
-<p>Once you have the Google Play services library project added to your app project,
-you can begin developing features with the
-<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
 
 
 
@@ -191,4 +274,4 @@
   to display an error message to the user, which allows the user to download the APK
   from the Google Play Store or enable it in the device's system settings.
     </li>
-</ol>
\ No newline at end of file
+</ol>
diff --git a/docs/html/google/play-services/wallet.jd b/docs/html/google/play-services/wallet.jd
index b9b98d9..9467be1 100644
--- a/docs/html/google/play-services/wallet.jd
+++ b/docs/html/google/play-services/wallet.jd
@@ -1,5 +1,5 @@
 page.title=Google Wallet Instant Buy for Android
-page.tags="Wallet","payments","Instant Buy"
+page.tags=Wallet,payments,Instant Buy
 header.hide=1
 
 @jd:body
@@ -83,4 +83,4 @@
 
 
   </div>
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/google/play/billing/gp-purchase-status-api.jd b/docs/html/google/play/billing/gp-purchase-status-api.jd
index 25ef28b..8db7133 100644
--- a/docs/html/google/play/billing/gp-purchase-status-api.jd
+++ b/docs/html/google/play/billing/gp-purchase-status-api.jd
@@ -1,5 +1,5 @@
 page.title=Purchase Status API
-page.tags="In-app Billing", "Google Play", "inapp billing", "in app billing", "iab", "billing"
+page.tags=In-app Billing,Google Play,inapp billing,in app billing,iab,billing
 
 @jd:body
 
@@ -58,7 +58,7 @@
 
 <p>The Purchase Status API is part of the <a
 href="https://developers.google.com/android-publisher/v1_1/">Google Play Android
-Developer API v1.1</a>, available through the Google APIs console. The new version
+Developer API v1.1</a>, available through the Google Cloud Console. The new version
 of the API supersedes the v1 API, which is deprecated. If you are using the v1
 API, please migrate your operations to the v1.1 API as soon as possible.</p>
 
@@ -66,7 +66,7 @@
 <h2 id="using">Using the API</h2>
 
 <p>To use the API, you must first register a project at the <a
-href="https://code.google.com/apis/console">Google APIs Console</a> and receive
+href="https://cloud.google.com/console">Google Cloud Console</a> and receive
 a Client ID and shared secret that  your app will present when calling the
 API. All calls are authenticated with OAuth 2.0.</p>
 
@@ -93,9 +93,9 @@
 subscription-validation needs, assuming that you follow the recommendation in
 this section.</p>
 
-<p>If you need to request a higher limit for your application, please use the
-“Request more” link in the <a
-href="https://code.google.com/apis/console/#:quotas">Google APIs Console</a>.
+<p>If you need to request a higher limit for your application, see the
+instructions in the <a
+href="https://developers.google.com/console/help/new/#trafficcontrols">Google Cloud Console Help</a>.
 Also, please read the section below on design best practices for minimizing your
 use of the API.</p>
 
diff --git a/docs/html/guide/appendix/media-formats.jd b/docs/html/guide/appendix/media-formats.jd
index 7c6c145..19f510a 100644
--- a/docs/html/guide/appendix/media-formats.jd
+++ b/docs/html/guide/appendix/media-formats.jd
@@ -1,5 +1,5 @@
 page.title=Supported Media Formats
-page.tags="video","audio","mpeg","mp4","m4a","mp3","3gp","3gpp","flac","wave","wav"
+page.tags=video,audio,mpeg,mp4,m4a,mp3,3gp,3gpp,flac,wave,wav
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
index 1cbaa79..b4617fb 100644
--- a/docs/html/guide/components/activities.jd
+++ b/docs/html/guide/components/activities.jd
@@ -1,5 +1,5 @@
 page.title=Activities
-page.tags="activity","intent"
+page.tags=activity,intent
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/components/processes-and-threads.jd b/docs/html/guide/components/processes-and-threads.jd
index 1fed712..c8c3764 100644
--- a/docs/html/guide/components/processes-and-threads.jd
+++ b/docs/html/guide/components/processes-and-threads.jd
@@ -1,5 +1,5 @@
 page.title=Processes and Threads
-page.tags="lifecycle","background"
+page.tags=lifecycle,background
 
 @jd:body
 
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 84ffd05..8f2795a 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -490,11 +490,8 @@
     <span class="en">Web Apps</span>
     </a></div>
     <ul>
-      <li><a href="<?cs var:toroot ?>guide/webapps/overview.html">
-            <span class="en">Overview</span>
-          </a></li>
       <li><a href="<?cs var:toroot ?>guide/webapps/targeting.html">
-            <span class="en">Targeting Screens from Web Apps</span>
+            <span class="en">Supporting Different Screens in Web Apps</span>
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/webapps/webview.html">
             <span class="en">Building Web Apps in WebView</span>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index a474498..ee6b814 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -1,5 +1,5 @@
 page.title=Device Administration
-page.tags="devicepolicymanager","policy","security"
+page.tags=devicepolicymanager,policy,security
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/appwidgets/host.jd b/docs/html/guide/topics/appwidgets/host.jd
index da7408f..169e388 100644
--- a/docs/html/guide/topics/appwidgets/host.jd
+++ b/docs/html/guide/topics/appwidgets/host.jd
@@ -1,5 +1,5 @@
 page.title=App Widget Host
-page.tags="AppWidgetHost","home screen","launcher"
+page.tags=AppWidgetHost,home screen,launcher
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index d8ad844..a783ad1 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -1,5 +1,5 @@
 page.title=App Widgets
-page.tags="home","AppWidgetProvider"
+page.tags=home,AppWidgetProvider
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/connectivity/bluetooth-le.jd b/docs/html/guide/topics/connectivity/bluetooth-le.jd
index 21950c2..fa0d36e 100644
--- a/docs/html/guide/topics/connectivity/bluetooth-le.jd
+++ b/docs/html/guide/topics/connectivity/bluetooth-le.jd
@@ -1,5 +1,5 @@
 page.title=Bluetooth Low Energy
-page.tags="wireless","bluetoothadapter","bluetoothdevice","BLE","BTLE"
+page.tags=wireless,bluetoothadapter,bluetoothdevice,BLE,BTLE
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/connectivity/bluetooth.jd b/docs/html/guide/topics/connectivity/bluetooth.jd
index b57f3e2..96008c5 100644
--- a/docs/html/guide/topics/connectivity/bluetooth.jd
+++ b/docs/html/guide/topics/connectivity/bluetooth.jd
@@ -1,5 +1,5 @@
 page.title=Bluetooth
-page.tags="wireless","bluetoothadapter","bluetoothdevice"
+page.tags=wireless,bluetoothadapter,bluetoothdevice
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/connectivity/nfc/hce.jd b/docs/html/guide/topics/connectivity/nfc/hce.jd
index d9063f3..76f7c7c 100644
--- a/docs/html/guide/topics/connectivity/nfc/hce.jd
+++ b/docs/html/guide/topics/connectivity/nfc/hce.jd
@@ -1,5 +1,5 @@
 page.title=Host-based Card Emulation
-page.tags="host card emulation", "hce","HostApduService","OffHostApduService","tap and pay"
+page.tags=host card emulation,hce,HostApduService,OffHostApduService,tap and pay
 
 @jd:body
 
@@ -70,7 +70,7 @@
 works.</p>
 
 <img src="{@docRoot}images/nfc/host-based-card.png" />
-<p class="img-caption"><strong>Figure 2.</strong> NFC card emulation with a secure element.</p>
+<p class="img-caption"><strong>Figure 2.</strong> NFC card emulation without a secure element.</p>
 
 
 <h2 id="SupportedProtocols">Supported NFC Cards and Protocols</h2>
@@ -178,7 +178,7 @@
 
 <p>Your application can check whether a device supports HCE by checking for the 
 {@link android.content.pm.PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} feature. You should use the 
-{@code &lt;uses-feature>} tag in the manifest of your application to declare that your app 
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature>}</a> tag in the manifest of your application to declare that your app 
 uses the HCE feature, and whether it is required for the app to function or not.</p>
 
 <h3 id="ServiceImplementation">Service implementation</h3>
@@ -288,12 +288,12 @@
 
 <pre>
 &lt;service android:name=".MyHostApduService" android:exported="true"
-        android:permission="android.permission.BIND_NFC_SERVICE">
+         android:permission="android.permission.BIND_NFC_SERVICE">
     &lt;intent-filter>
         &lt;action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
     &lt;/intent-filter>
     &lt;meta-data android:name="android.nfc.cardemulation.host_apdu_service"
-        android:resource="@xml/apduservice"/>
+               android:resource="@xml/apduservice"/>
 &lt;/service>
 </pre>
 
@@ -306,7 +306,7 @@
            android:description="@string/servicedesc" 
            android:requireDeviceUnlock="false">
     &lt;aid-group android:description="@string/aiddescription" 
-                android:category="other">
+               android:category="other">
         &lt;aid-filter android:name="F0010203040506"/>
         &lt;aid-filter android:name="F0394148148100"/>
     &lt;/aid-group>
@@ -381,14 +381,14 @@
 
 <pre>
 &lt;host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
-           android:description="@string/servicedesc" 
-           android:requireDeviceUnlock="false"
-           android:apduServiceBanner="@drawable/my_banner">
-       &lt;aid-group android:description="@string/aiddescription"
-                  android:category="payment">
-           &lt;aid-filter android:name="F0010203040506"/>
-           &lt;aid-filter android:name="F0394148148100"/>
-       &lt;/aid-group>
+        android:description="@string/servicedesc" 
+        android:requireDeviceUnlock="false"
+        android:apduServiceBanner="@drawable/my_banner">
+    &lt;aid-group android:description="@string/aiddescription"
+               android:category="payment">
+        &lt;aid-filter android:name="F0010203040506"/>
+        &lt;aid-filter android:name="F0394148148100"/>
+    &lt;/aid-group>
 &lt;/host-apdu-service>
 </pre>
 
@@ -478,12 +478,12 @@
 
 <pre>
 &lt;service android:name=".MyOffHostApduService" android:exported="true"
-     android:permission="android.permission.BIND_NFC_SERVICE">
+         android:permission="android.permission.BIND_NFC_SERVICE">
     &lt;intent-filter>
         &lt;action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/>
     &lt;/intent-filter>
     &lt;meta-data android:name="android.nfc.cardemulation.off_host_apdu_ervice"
-         android:resource="@xml/apduservice"/>
+               android:resource="@xml/apduservice"/>
 &lt;/service>
 </pre>
 </li>
diff --git a/docs/html/guide/topics/connectivity/sip.jd b/docs/html/guide/topics/connectivity/sip.jd
index 526eb83..5154767 100644
--- a/docs/html/guide/topics/connectivity/sip.jd
+++ b/docs/html/guide/topics/connectivity/sip.jd
@@ -1,5 +1,5 @@
 page.title=Session Initiation Protocol
-page.tags="sipmanager","sipprofile","sipaudiocall","telephony"
+page.tags=sipmanager,sipprofile,sipaudiocall,telephony
 @jd:body
 <div id="qv-wrapper">
 <div id="qv">
diff --git a/docs/html/guide/topics/connectivity/wifip2p.jd b/docs/html/guide/topics/connectivity/wifip2p.jd
index 7cadde1..d7e1269 100644
--- a/docs/html/guide/topics/connectivity/wifip2p.jd
+++ b/docs/html/guide/topics/connectivity/wifip2p.jd
@@ -1,5 +1,5 @@
 page.title=Wi-Fi Peer-to-Peer
-page.tags="wireless","WifiP2pManager","Wi-Fi Direct","WiFi Direct","P2P","Wi-Fi P2P","WiFi P2P"
+page.tags=wireless,WifiP2pManager,Wi-Fi Direct,WiFi Direct,P2P,Wi-Fi P2P,WiFi P2P
 
 @jd:body
 
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 385c116..6fca02f0 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -1,5 +1,5 @@
 page.title=Storage Options
-page.tags="database","sharedpreferences","sdcard"
+page.tags=database,sharedpreferences,sdcard
 @jd:body
 
 
diff --git a/docs/html/guide/topics/data/install-location.jd b/docs/html/guide/topics/data/install-location.jd
index 2ec0d5a..cc58b46 100644
--- a/docs/html/guide/topics/data/install-location.jd
+++ b/docs/html/guide/topics/data/install-location.jd
@@ -1,5 +1,5 @@
 page.title=App Install Location
-page.tags="sdcard","external"
+page.tags=sdcard,external
 @jd:body
 
 
diff --git a/docs/html/guide/topics/graphics/opengl.jd b/docs/html/guide/topics/graphics/opengl.jd
index f46113d..d194082 100644
--- a/docs/html/guide/topics/graphics/opengl.jd
+++ b/docs/html/guide/topics/graphics/opengl.jd
@@ -1,5 +1,5 @@
 page.title=OpenGL ES
-page.tags="games"
+page.tags=games
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/graphics/prop-animation.jd b/docs/html/guide/topics/graphics/prop-animation.jd
index 22bf7696..e455496 100644
--- a/docs/html/guide/topics/graphics/prop-animation.jd
+++ b/docs/html/guide/topics/graphics/prop-animation.jd
@@ -1,5 +1,5 @@
 page.title=Property Animation
-page.tags="valueanimator","objectanimator","layouttransition","ViewPropertyAnimator"
+page.tags=valueanimator,objectanimator,layouttransition,ViewPropertyAnimator
 @jd:body
 
   <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/manifest/uses-configuration-element.jd b/docs/html/guide/topics/manifest/uses-configuration-element.jd
index 810975e..e9a0ba4 100644
--- a/docs/html/guide/topics/manifest/uses-configuration-element.jd
+++ b/docs/html/guide/topics/manifest/uses-configuration-element.jd
@@ -6,18 +6,18 @@
 <!-- ##api level 3##  see comment below -->
 
 <!-- the "no___" values are nonsensical if they mean "doesn't work on devices with a
-keyboard / navigation control / touch screen."  Dianne says that that's what they mean and 
-that they therefore should be eliminated.  Suchi says that they mean "doesn't require a 
+keyboard / navigation control / touch screen."  Dianne says that that's what they mean and
+that they therefore should be eliminated.  Suchi says that they mean "doesn't require a
 keyboard / navigation control / touch screen to work."  But then what does "undefined" mean?
 Seems like some API change is in the works, either eliminating the "no___" values or
-"undefined".  Since it's unclear what the change will be, I've chosen to document the "no___" 
+"undefined".  Since it's unclear what the change will be, I've chosen to document the "no___"
 and "undefined" attributes using the same language, which is surely wrong but may make it
-easier to update the doc when the change is made. -->
+easier to update the doc when the change is made... Nov 2013, this still seems unresolved. -->
 
 <dl class="xml">
 <dt>syntax:</dt>
 <dd><pre class="stx">&lt;uses-configuration
-  android:<a href="#five">reqFiveWayNav</a>=["true" | "false"] 
+  android:<a href="#five">reqFiveWayNav</a>=["true" | "false"]
   android:<a href="#hard">reqHardKeyboard</a>=["true" | "false"]
   android:<a href="#kbd">reqKeyboardType</a>=["undefined" | "nokeys" | "qwerty" | "twelvekey"]
   android:<a href="#nav">reqNavigation</a>=["undefined" | "nonav" | "dpad" | "trackball" | "wheel"]
@@ -27,38 +27,35 @@
 <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
 
 <dt>description:</dt>
-<dd>Indicates what hardware and software features the application requires.  
-For example, an application might specify that it requires a physical keyboard 
+<dd>Indicates what hardware and software features the application requires.
+For example, an application might specify that it requires a physical keyboard
 or a particular navigation device, like a trackball.  The specification is
 used to avoid installing the application on devices where it will not work.
 
-<p>
-If an application can work with different device configurations, it 
-should include separate {@code &lt;uses-configuration&gt;} declarations for 
-each one.  Each declaration must be complete.  For example, if an application 
-requires a five-way navigation control, a touch screen that can be operated 
-with a finger, and either a standard QWERTY keyboard or a numeric 12-key
-keypad like those found on most phones, it would specify these requirements
-with two {@code &lt;uses-configuration&gt;} elements as follows:
-</p>
+<p class="note"><strong>Note: Most apps should not use this manifest tag.</strong> You should
+<em>always</em> support input with a directional pad (d-pad) in order to assist sight-impaired
+users and support devices that provide d-pad input in addition to or instead of touch. For
+information about how to support d-pad input in your app, read <a href=
+"{@docRoot}guide/topics/ui/accessibility/apps.html#focus-nav">Enabling Focus Navigation</a>. If
+your app absolutely cannot function without a touchscreen, then instead use the <a href=
+"{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature&gt;}</a> tag to
+declare the required touchscreen type, ranging from {@code "android.hardware.faketouch"} for basic
+touch-style events to more advanced touch types such as {@code
+"android.hardware.touchscreen.multitouch.jazzhand"} for distinct input from multiple fingers.</p>
 
-<pre>&lt;uses-configuration android:reqFiveWayNav="true" android:reqTouchScreen="finger"
-                    android:reqKeyboardType="qwerty" /&gt;
-&lt;uses-configuration android:reqFiveWayNav="true" android:reqTouchScreen="finger"
-                    android:reqKeyboardType="twelvekey" /&gt;</pre></dd>
 
 <dt>attributes:</dt>
 <dd><dl class="attr">
 <dt><a name="five"></a>{@code android:reqFiveWayNav}</dt>
-<dd>Whether or not the application requires a five-way navigation control 
+<dd>Whether or not the application requires a five-way navigation control
 &mdash; "{@code true}" if it does, and "{@code false}" if not.  A five-way
-control is one that can move the selection up, down, right, or left, and 
-also provides a way of invoking the current selection.  It could be a 
-D-pad (directional pad), trackball, or other device.  
+control is one that can move the selection up, down, right, or left, and
+also provides a way of invoking the current selection.  It could be a
+D-pad (directional pad), trackball, or other device.
 
 <p>
 If an application requires a directional control, but not a control of a
-particular type, it can set this attribute to "{@code true}" and ignore 
+particular type, it can set this attribute to "{@code true}" and ignore
 the <code><a href="#nav">reqNavigation</a></code> attribute.  However,
 if it requires a particular type of directional control, it can ignore
 this attribute and set {@code reqNavigation} instead.
@@ -69,10 +66,10 @@
 "{@code true}" if it does, and "{@code false}" if not.</dd>
 
 <dt><a name="kbd"></a>{@code android:reqKeyboardType}</dt>
-<dd>The type of keyboard the application requires, if any at all. 
-This attribute does not distinguish between hardware and software 
+<dd>The type of keyboard the application requires, if any at all.
+This attribute does not distinguish between hardware and software
 keyboards.  If a hardware keyboard of a certain type is required,
-specify the type here and also set the {@code reqHardKeyboard} attribute 
+specify the type here and also set the {@code reqHardKeyboard} attribute
 to "{@code true}".
 
 <p>
@@ -85,8 +82,8 @@
    <th>Description</th>
 </tr><tr>
    <td>"{@code undefined}"</td>
-   <td>The application does not require a keyboard. 
-       (A keyboard requirement is not defined.)  
+   <td>The application does not require a keyboard.
+       (A keyboard requirement is not defined.)
        This is the default value.</td>
 </tr><tr>
    <td>"{@code nokeys}"</td>
@@ -96,14 +93,14 @@
    <td>The application requires a standard QWERTY keyboard.</td>
 </tr><tr>
    <td>"{@code twelvekey}"</td>
-   <td>The application requires a twelve-key keypad, like those on most 
-       phones &mdash; with keys for the digits from {@code 0} through 
+   <td>The application requires a twelve-key keypad, like those on most
+       phones &mdash; with keys for the digits from {@code 0} through
        {@code 9} plus star ({@code *}) and pound ({@code #}) keys.</td>
 </tr>
 </table></dd>
 
 <dt><a name="nav"></a>{@code android:reqNavigation}</dt>
-<dd>The navigation device required by the application, if any.  The value 
+<dd>The navigation device required by the application, if any.  The value
 must be one of the following strings:
 
 <table>
@@ -112,8 +109,8 @@
    <th>Description</th>
 </tr><tr>
    <td>"{@code undefined}"</td>
-   <td>The application does not require any type of navigation control. 
-       (The navigation requirement is not defined.)  
+   <td>The application does not require any type of navigation control.
+       (The navigation requirement is not defined.)
        This is the default value.</td>
 </tr><tr>
    <td>"{@code nonav}"</td>
@@ -132,14 +129,14 @@
 
 <p>
 If an application requires a navigational control, but the exact type of
-control doesn't matter, it can set the 
+control doesn't matter, it can set the
 <code><a href="#five">reqFiveWayNav</a></code> attribute to "{@code true}"
 rather than set this one.
 </p></dd>
 
 <dt><a name="touch"></a>{@code android:reqTouchScreen}</dt>
 <dd>The type of touch screen the application requires, if any at all.
-The value must be one of the following strings: 
+The value must be one of the following strings:
 
 <table>
 <tr>
@@ -147,7 +144,7 @@
    <th>Description</th>
 </tr><tr>
    <td>"{@code undefined}"</td>
-   <td>The application doesn't require a touch screen.  
+   <td>The application doesn't require a touch screen.
        (The touch screen requirement is undefined.)
        This is the default value.</td>
 </tr><tr>
@@ -158,7 +155,14 @@
    <td>The application requires a touch screen that's operated with a stylus.</td>
 </tr><tr>
    <td>"{@code finger}"</td>
-   <td>The application requires a touch screen that can be operated with a finger.</td>
+   <td>The application requires a touch screen that can be operated with a finger.
+
+      <p class="note"><strong>Note:</strong> If some type of touch input is required for your app,
+      you should instead use the
+      <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code
+      &lt;uses-feature>}</a> tag to declare the required touchscreen
+      type, beginning with {@code "android.hardware.faketouch"} for basic touch-style events.</p>
+   </td>
 </tr>
 </table></dd>
 </dl></dd>
@@ -172,7 +176,7 @@
   <ul>
     <li><code><a href="{@docRoot}guide/topics/manifest/activity-element.html#config">configChanges</a></code>
 attribute of the
-<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code> 
+<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
 element</dd></li>
     <li>{@link android.content.pm.ConfigurationInfo}</li>
   </ul>
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 95f62a5..445d5ce 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -1,5 +1,5 @@
 page.title=&lt;uses-feature&gt;
-page.tags="filtering","features","google play filters","permissions"
+page.tags=filtering,features,google play filters,permissions
 @jd:body
 
 <div id="qv-wrapper">
@@ -1071,4 +1071,4 @@
   <td><code>android.hardware.wifi</code></td>
 <!--  <td></td> -->
 </tr>
-</table>
\ No newline at end of file
+</table>
diff --git a/docs/html/guide/topics/manifest/uses-permission-element.jd b/docs/html/guide/topics/manifest/uses-permission-element.jd
index 8e9e795..bd7091e 100644
--- a/docs/html/guide/topics/manifest/uses-permission-element.jd
+++ b/docs/html/guide/topics/manifest/uses-permission-element.jd
@@ -35,7 +35,8 @@
 </div>
 
 <dt>syntax:</dt>
-<dd><pre class="stx">&lt;uses-permission android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+<dd><pre class="stx">&lt;uses-permission android:<a href="#nm">name</a>="<i>string</i>"
+        android:<a href="#maxSdk">maxSdkVersion</a>="<i>integer</i>" /&gt;</pre></dd>
 
 <dt>contained in:</dt>
 <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
@@ -63,6 +64,25 @@
 or "{@code android.permission.READ_CONTACTS}".  As these examples show, 
 a permission name typically includes the package name as a prefix.</dd>
 
+<dt><a name="maxSdk"></a>{@code android:maxSdkVersion}</dt>
+<dd>The highest API level at which this permission should be granted to your app.
+Setting this attribute is useful if the permission your app requires is no longer needed beginning
+at a certain API level.
+<p>For example, beginning with Android 4.4 (API level 19), it's no longer necessary for your app
+to request the {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission when your
+app wants to write to its own application-specific directories on external storage (the directories
+provided by {@link android.content.Context#getExternalFilesDir getExternalFilesDir()}). However,
+the permission <em>is required</em> for API level 18 and lower. So you can declare that this
+permission is needed only up to API level 18 with a declaration such as this:
+<pre>
+&lt;uses-permission
+     android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+     android:maxSdkVersion="18" />
+</pre>
+<p>This way, beginning with API level 19, the system will no longer grant your app the
+{@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.</p>
+</dd>
+
 </dl></dd>
 
 <!-- ##api level indication## -->
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index 9169658..dd5ea86 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -1,5 +1,5 @@
 page.title=&lt;uses-sdk&gt;
-page.tags="api levels","sdk version","minsdkversion","targetsdkversion","maxsdkversion"
+page.tags=api levels,sdk version,minsdkversion,targetsdkversion,maxsdkversion
 @jd:body
 
 
diff --git a/docs/html/guide/topics/media/audio-capture.jd b/docs/html/guide/topics/media/audio-capture.jd
index 44c618f..8e60c8f 100644
--- a/docs/html/guide/topics/media/audio-capture.jd
+++ b/docs/html/guide/topics/media/audio-capture.jd
@@ -1,5 +1,5 @@
 page.title=Audio Capture
-page.tags="mediarecorder"
+page.tags=mediarecorder
 @jd:body
 
     <div id="qv-wrapper">
@@ -249,4 +249,4 @@
         }
     }
 }
-</pre>
\ No newline at end of file
+</pre>
diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
index e48109a..56ef624 100644
--- a/docs/html/guide/topics/media/camera.jd
+++ b/docs/html/guide/topics/media/camera.jd
@@ -1,5 +1,5 @@
 page.title=Camera
-page.tags="photo","video","picture","mediarecorder"
+page.tags=photo,video,picture,mediarecorder
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/media/mediaplayer.jd b/docs/html/guide/topics/media/mediaplayer.jd
index fb272d2..63c04a2 100644
--- a/docs/html/guide/topics/media/mediaplayer.jd
+++ b/docs/html/guide/topics/media/mediaplayer.jd
@@ -1,5 +1,5 @@
 page.title=Media Playback
-page.tags="mediaplayer","soundpool","audiomanager"
+page.tags=mediaplayer,soundpool,audiomanager
 @jd:body
 
     <div id="qv-wrapper">
@@ -743,4 +743,4 @@
 mMediaPlayer.setDataSource(getApplicationContext(), contentUri);
 
 // ...prepare and start...
-</pre>
\ No newline at end of file
+</pre>
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 55c8dc42..3bb9ab5 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -1,483 +1,485 @@
-page.title=Localizing with Resources

-parent.title=Application Resources

-page.tags="localizing","localization","resources", "formats", "l10n"

-parent.link=index.html

-@jd:body

-

-<div id="qv-wrapper">

-    <div id="qv">

-

-<h2>Quickview</h2>

-

-<ul>

-  <li>Use resource sets to create a localized app.</li>

-  <li>Android loads the correct resource set for the user's language and locale.</li>

-  <li>If localized resources are not available, Android loads your default resources.</li>

-</ul>

-

-<h2>In this document</h2>

-<ol>

-  <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>

-<li><a href="#using-framework">Using Resources for Localization</a></li>

-<li><a href="#strategies">Localization Strategies</a></li>

-<li><a href="#testing">Testing Localized Applications</a></li>

-</ol>

-

-<h2>See also</h2>

-  <ol>

-    <li><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>

-    <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>

-    <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>

-    <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>

-</ol>

-</div>

-</div>

-

-<p>Android will run on many  devices in many  regions. To reach the most users,

-your application should handle text, audio files, numbers, currency, and

-graphics in ways appropriate to the locales where your application will be used.

-</p>

-

-<p>This document describes best practices for localizing Android

-applications. The principles apply whether you are developing your application  

-using ADT with Eclipse, Ant-based tools, or any other IDE. </p>

-

-<p>You should already have a working knowledge of Java and be  familiar with

-Android resource loading, the declaration of user interface elements in XML,

-development considerations such as Activity lifecycle, and general principles of

-internationalization and localization. </p>

-

-<p>It is good practice to use the Android resource framework to separate the

-localized aspects of your application as much as possible from the core Java

-functionality:</p>

-

-<ul>

-  <li>You can put most or all of the <em>contents</em> of your application's

-user interface into resource files, as described in this document and in <a

-href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>

-  <li>The <em>behavior</em> of the user interface, on the other hand, is driven

-by your Java code. 

-    For example, if users input data that needs to be formatted or sorted

-differently depending on locale, then you would use Java to handle the data

-programmatically. This document does not cover how to  localize your Java code.

-</li>

-</ul>

-

-<p>For a short guide to localizing strings in your app, see the training lesson, <a

-href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>

-

-

-<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>

-

-<p>Resources are text strings, layouts, sounds, graphics, and any other static

-data that your  Android application  needs. An application can include multiple

-sets of resources, each customized for a different device configuration. When a

-user runs the application,  Android    automatically selects and loads the 

-resources that best match the device.</p>

-

-<p>(This document focuses on localization and locale. For a complete description

-of resource-switching and all the types of configurations that you can

-specify &#8212; screen orientation, touchscreen type, and so on &#8212; see <a

-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing

-Alternative Resources</a>.)</p>

-

-<table border="0" cellspacing="0" cellpadding="0">

-  <tr border="0">

-    <td width="180" style="border: 0pt none ;"><p class="special-note">

-    <strong>When you write your application:</strong>

-    <br><br>

-    You create a set of default resources, plus alternatives to be used in

-    different locales.</p></td>

-    <td style="border: 0pt none; padding:0">

-    <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow" 

-    width="51" height="17"></p></td>

-    <td width="180" style="border: 0pt none ;"><p class="special-note">

-    <strong>When a user runs your application:</strong>

-    <br><br>The Android system selects which resources to load, based on the

-    device's locale.</p></td>

-  </tr>

-</table>

-

-<p>When you write your application, you create default and alternative resources

-for your application to use. To create  resources, you place files within

-specially named subdirectories of the project's <code>res/</code> directory.

-</p>

-

-

-

-<h3 id="defaults-r-important">Why Default Resources Are Important</h3>

-

-<p>Whenever the application runs in a locale for which you have not provided

-locale-specific text,  Android will load the default strings from

-<code>res/values/strings.xml</code>. If this default  file is absent, or if it 

-is missing a string that your application needs, then your application will not run 

-and will show an error. 

-The example below illustrates what can happen when the default text file is incomplete. </p>

-

-<p><em>Example:</em>

-<p>An application's Java code refers to just two strings, <code>text_a</code> and 

-	<code>text_b</code>. This application includes a localized resource file 

-	(<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and 

-	<code>text_b</code> in English. This application also includes a default 

-	resource file (<code>res/values/strings.xml</code>) that includes a

-definition for <code>text_a</code>, but not for <code>text_b</code>:

-<ul>

-  <li>This application might compile without a problem. An IDE such as Eclipse 

-  	will not highlight any errors if a resource is missing.</li>

-  <li>When this application is launched on a device with locale set to English, 

-  	the application  might run without a problem, because 

-  	<code>res/values-en/strings.xml</code> contains both of the needed text 

-  	strings.</li>

-  <li>However, <strong>the user  will see an error message and a Force Close 

-  	button</strong> when this application is launched on a device set to a 

-  	language other than English. The application will not load.</li>

-</ul>

-

-

-<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code> 

-	file exists and that it defines every needed string. The situation applies to 

-	all types of resources, not just strings: You 

-	need to create a  set of default resource files containing all 

-	the resources that your application calls upon &#8212; layouts, drawables, 

-	animations, etc. For information about testing, see <a href="#test-for-default">

-	Testing for Default Resources</a>.</p>

-

-<h2 id="using-framework">Using Resources for Localization</h2>

-

-<h3 id="creating-defaults">How to Create Default Resources</h3>

-

-<p>Put the application's default text in

-a file with the following location and name:</p>

-<p><code>&nbsp;&nbsp;&nbsp;&nbsp;res/values/strings.xml</code> (required directory)</p>

-

-<p>The text strings in <code>res/values/strings.xml</code> should  use the

-default language, which is the language that you expect most of your application's users to

-speak.  </p>

-

-<p>The default resource set must also include any default drawables and layouts, 

-	and can include other types of resources such as animations. 

-<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/drawable/</code>(required directory holding at least

-  one graphic file, for the application's icon on Google Play)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/layout/</code> (required directory holding an XML

-  file that defines the default layout)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/anim/</code> (required if you have any 

-  <code>res/anim-<em>&lt;qualifiers&gt;</em></code> folders)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/xml/</code> (required if you have any 

-  <code>res/xml-<em>&lt;qualifiers&gt;</em></code> folders)<br>

-  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/raw/</code> (required if you have any 

-  <code>res/raw-<em>&lt;qualifiers&gt;</em></code> folders)

-</p>

-

-<p class="note"><strong>Tip:</strong> In your code, examine each reference to 

-	an Android resource. Make sure that a default resource is defined for each

-	one. Also make sure that the default string file is complete: A <em>

-	localized</em> string file can contain a subset of the strings, but the 

-	<em>default</em> string file must contain them all. 

-</p>

-

-<h3 id="creating-alternatives">How to Create Alternative Resources</h3>

-

-<p>A large part of localizing an application is providing alternative text for

-different languages. In some cases you will also provide alternative graphics,

-sounds, layouts, and other locale-specific resources. </p>

-

-<p>An application can specify many <code>res/<em>&lt;qualifiers&gt;</em>/</code>

-directories, each with different qualifiers. To create an alternative resource for

-a different locale, you use a qualifier that specifies a language or a 

-language-region combination. (The name of a resource directory must conform 

-to the naming scheme described in 

-<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing

-Alternative Resources</a>,

-or else it will not compile.)</p>

-

-<p><em>Example:</em></p>

-

-<p>Suppose that your application's default language is English. Suppose also

-that you want to localize all the text in your application to French, and most

-of the text in your application (everything except the application's title) to

-Japanese. In this case, you could create three alternative <code>strings.xml</code>

-files, each stored in a locale-specific resource directory:</p>

-

-<ol>

-  <li><code>res/values/strings.xml</code><br>

-    Contains  English text for all  the strings that the application uses,

-including text for a string named <code>title</code>.</li>

-  <li><code>res/values-fr/strings.xml</code><br>

-    Contain French text for all  the strings, including <code>title</code>.</li>

-  <li><code>res/values-ja/strings.xml</code><br>

-    Contain Japanese text for all  the strings <em>except</em>

-<code>title</code>.<br>

-  <code></code></li>

-</ol>

-

-<p>If your Java code refers to <code>R.string.title</code>,  here is what will

-happen at runtime:</p>

-

-<ul>

-  <li>If the device is set to any language other than French, Android will load

-<code>title</code> from the <code>res/values/strings.xml</code> file.</li>

-  <li>If the device is set to French, Android will load <code>title</code> from

-the <code>res/values-fr/strings.xml</code> file.</li>

-</ul>

-

-<p>Notice that if the device is set to Japanese, Android will look for

-<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But

-because no such string is included in that file, Android will fall back to the

-default, and will load  <code>title</code> in English from the

-<code>res/values/strings.xml</code> file.  </p>

-

-<h3 id="resource-precedence">Which Resources Take Precedence?</h3>

-

-<p> If multiple resource files match a device's configuration, Android follows a

-set of rules in deciding which file to use. Among the qualifiers that can be

-specified in a resource directory name, <strong>locale almost always takes

-precedence</strong>. </p>

-<p><em>Example:</em></p>

-

-<p>Assume that an application  includes a default set of graphics and two other

-sets of graphics, each optimized for a different device setup:</p>

-

-<ul>

-  <li><code>res/drawable/</code><br>

-    Contains

-  default graphics.</li>

-  <li><code>res/drawable-small-land-stylus/</code><br>

-  Contains  graphics optimized for use with a device that expects input from a 

-  stylus and has a QVGA low-density screen in landscape orientation.</li>

-  <li><code>res/drawable-ja/</code> <br>

-  Contains  graphics optimized for use with Japanese.</li>

-</ul>

-

-<p>If the application runs on a device that is configured to use Japanese,

-Android will load graphics from  <code>res/drawable-ja/</code>, even if the

-device happens to be one that expects input from a stylus and has a QVGA 

-low-density screen in landscape orientation.</p>

-

-<p class="note"><strong>Exception:</strong> The only qualifiers that take

-precedence over locale in the selection process are MCC and MNC (mobile country

-code and mobile network code). </p>

-

-<p><em>Example:</em></p>

-

-<p>Assume that you have the following situation:</p>

-

-<ul>

-  <li>The application code calls for <code>R.string.text_a</code></li>

-  <li>Two relevant resource files are available:

-    <ul>

-      <li><code>res/values-mcc404/strings.xml</code>, which includes

-<code>text_a</code> in the application's default language, in this case

-English.</li>

-      <li><code>res/values-hi/strings.xml</code>, which includes

-<code>text_a</code> in Hindi.</li>

-    </ul>

-  </li>

-  <li>The application is running on a device that has the following

-configuration:

-    <ul>

-      <li>The SIM card is connected to a mobile network in India (MCC 404).</li>

-      <li>The language is set to Hindi (<code>hi</code>).</li>

-    </ul>

-  </li>

-</ul>

-

-<p>Android will load <code>text_a</code> from

-<code>res/values-mcc404/strings.xml</code> (in English), even if the device is

-configured for Hindi. That is because in the resource-selection process, Android

-will prefer an MCC match over a language match. </p>

-

-<p>The selection process is not always as straightforward as these examples

-suggest. Please read  <a

-href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds

-the Best-matching Resource</a> for a more nuanced description of the

-process. All the qualifiers are described and listed in order of

-precedence in <a

-href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing

-Alternative Resources</a>.</p>

-

-<h3 id="referring-to-resources">Referring to Resources in Java</h3>

-

-<p>In your application's Java code, you refer to  resources using the syntax

-<code>R.<em>resource_type</em>.<em>resource_name</em></code> or

-<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>

-For more about this, see <a

-href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>

-

-<h2 id="strategies">Localization Strategies</h2>

-

-<h4 id="failing2">Design your application  to work in any locale</h4>

-

-<p>You cannot assume anything about the device on which a user will

-run your application. The device might have hardware that you were not

-anticipating, or it might be set to a locale that you did not plan for or that 

-you cannot test. Design your application so that it will function normally or fail gracefully no 

-matter what device it runs on.</p>

-

-<p class="note"><strong>Important:</strong> Make sure that your application

-includes a full set of default resources.</p> <p>Make sure to include

-<code>res/drawable/</code> and a <code>res/values/</code> folders (without any

-additional modifiers in the folder names) that contain all the images and text

-that your application will need. </p>

-

-<p>If an application is missing even one default resource, it will not run on a 

-	device that is set to an unsupported locale. For example, the 

-	<code>res/values/strings.xml</code> default file might lack one string that 

-	the application needs: When the application runs in an unsupported locale and 

-	attempts to load <code>res/values/strings.xml</code>, the user will see an 

-	error message and a Force Close button. An IDE such as Eclipse will not 

-	highlight this kind of error, and you will not see the problem when you 

-	test the application on a device or emulator that is set to a supported locale.</p>

-

-<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>

-

-<h4>Design a flexible layout</h4>

-

-<p> If you need to rearrange your layout to fit a certain language (for example

-German with its long words), you can create an alternative layout for that

-language (for example <code>res/layout-de/main.xml</code>). However, doing this

-can make your application harder to maintain.  It is better to create a single

-layout that is more flexible.</p>

-

-<p>Another typical situation is a language that requires something different in

-its layout. For example, you might have a contact form that should include  two

-name fields when the application runs in Japanese, but three name fields when

-the application  runs in some other language. You could handle this in either of

-two ways:</p>

-

-<ul>

-  <li>Create  one  layout with a field that you can programmatically enable or

-disable, based on the language, or</li>

-  <li>Have the main layout include another layout that  includes the changeable

-field. The second layout can have different configurations for different

-languages.</li>

-</ul>

-

-<h4>Avoid creating more resource files and text strings than you need</h4>

-

-<p>You probably do not need to create a locale-specific

-alternative for every resource in your application. For example, the layout

-defined in the <code>res/layout/main.xml</code> file might work in any locale,

-in which case there would be no need to create any alternative layout files.

-</p>

-

-<p>Also, you might not need to create alternative text for every

-string. For example, assume the following:</p>

-

-<ul>

-  <li>Your application's default language is American

-English. Every string that the application uses is defined, using American

-English spellings, in <code>res/values/strings.xml</code>. </li>

-

-  <li>For  a few important phrases, you want to provide

-British English spelling. You want these alternative strings to be used when your

-application runs on a device in the United Kingdom. </li>

-</ul>

-

-<p>To do this, you could create a small file called

-<code>res/values-en-rGB/strings.xml</code> that includes only the strings that

-should be different when the application  runs in the U.K. For all the rest of

-the strings, the application will fall back to the defaults and use what is

-defined in <code>res/values/strings.xml</code>.</p>

-

-<h4>Use the Android Context object for manual locale lookup</h4>

-

-<p>You can look up the locale using the {@link android.content.Context} object

-that Android makes available:</p>

-

-<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>

-

-<h2 id="testing">Testing Localized Applications</h2>

-

-<h3 id="device">Testing on a Device</h3>

-<p>Keep in mind that the device you are testing may be significantly different from 

-	the devices available to consumers in other geographies. The locales available 

-	on your device may differ from those available on other devices. Also, the 

-	resolution and density of the device screen may differ, which could affect 

-	the display of strings and drawables in your UI.</p>

-

-<p>To change the locale on a device, use  the Settings application  (Home &gt;

-Menu &gt; Settings &gt; Locale &amp; text &gt; Select locale). </p>

-

-<h3 id="emulator">Testing on an Emulator</h3>

-

-<p>For details about using the emulator, see See <a

-href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>

-<h4>Creating and using a custom locale</h4>

-

-<p>A &quot;custom&quot; locale is a language/region combination that the Android

-system image does not explicitly support. (For a list of supported locales in

-Android platforms see the Version Notes in the <a

-href="{@docRoot}sdk/index.html">SDK</a> tab). You can test

-how your application will run in a custom locale by creating a custom locale in

-the emulator. There are two ways to do this:</p>

-

-<ul>

-  <li>Use the Custom Locale application, which is accessible from the

-Application tab. (After you create a custom locale, switch to it by 

-pressing and holding the locale name.)</li>

-  <li>Change to a custom locale from the adb shell, as described below.</li>

-</ul>

-

-<p>When you set the emulator to a locale that is not available in the Android

-system image, the system itself will display in its default language. Your

-application, however, should localize properly.</p>

-

-<h4>Changing the emulator locale from the adb shell</h4>

-

-<p>To change the locale in the emulator by using the adb shell. </p>

-

-<ol>

-  <li>Pick the locale you want to test and determine its language and region codes, for

-example <code>fr</code> for French and <code>CA</code> for Canada.<br>

-  </li>

-  <li>Launch an emulator.</li>

-  <li>From a command-line shell on the host computer, run the following

-command:<br>

-    <code>adb shell</code><br>

-  or if you have a device attached, specify that you want the emulator by adding

-the <code>-e</code> option:<br>

-  <code>adb -e shell</code></li>

-  <li>At  the  adb shell prompt (<code>#</code>), run this command: <br>

-    <code>setprop persist.sys.language  [<em>language code</em>];setprop

-persist.sys.country [<em>country  code</em>];stop;sleep 5;start <br>

-    </code>Replace bracketed sections with the  appropriate codes from Step

-1.</li>

-</ol>

-

-<p>For instance, to test in Canadian French:</p>

-

-<p><code>setprop persist.sys.language  fr;setprop persist.sys.country

-CA;stop;sleep 5;start </code></p>

-

-<p>This will cause the emulator  to restart. (It will look like a full reboot,

-but it is not.) Once the Home screen appears again, re-launch your application (for

-example, click the Run icon in Eclipse), and the application will launch with

-the new locale. </p>

-

-<h3 id="test-for-default">Testing for Default Resources</h3>

-<p>Here's how to test whether an application includes every string resource that it needs:  </p>

-<ol><li>Set the emulator or device to a language that your application does not 

-	support. For example, if the application has French strings in 

-	<code>res/values-fr/</code> but does not have any Spanish strings in 

-	<code>res/values-es/</code>, then set the emulator's locale to Spanish. 

-	(You can use the Custom Locale application to set the emulator to an 

-	unsupported locale.)</li>

-	<li>Run the application.</li>  

-<li>If the application shows an error message and a Force Close button, it might 

-	be looking for a string that is not available. Make sure that your 

-	<code>res/values/strings.xml</code> file includes a definition for 

-	every string that the application uses.</li>

-</ol> 

-</p> 

-

-<p>If the test is successful, repeat it for other types of 

-	configurations. For example, if the application has a layout file called 

-	<code>res/layout-land/main.xml</code> but does not contain a file called 

-	<code>res/layout-port/main.xml</code>, then set the emulator or device to 

-	portrait orientation and see if the application will run. 

-

-

-<h2 id="checklist">Localization Checklist</h2>

-

-<p>For an overview of the process of localizing an Android application, see the <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a>.</p>

+page.title=Localizing with Resources
+parent.title=Application Resources
+page.tags=localizing,localization,resources,formats,l10n
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+    <div id="qv">
+
+<h2>Quickview</h2>
+
+<ul>
+  <li>Use resource sets to create a localized app.</li>
+  <li>Android loads the correct resource set for the user's language and locale.</li>
+  <li>If localized resources are not available, Android loads your default resources.</li>
+</ul>
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#resource-switching">Overview: Resource-Switching in Android</a></li>
+<li><a href="#using-framework">Using Resources for Localization</a></li>
+<li><a href="#strategies">Localization Tips</a></li>
+<li><a href="#testing">Testing Localized Applications</a></li>
+</ol>
+
+<h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
+    <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>
+    <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>
+    <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>
+</ol>
+</div>
+</div>
+
+<p>Android will run on many  devices in many  regions. To reach the most users,
+your application should handle text, audio files, numbers, currency, and
+graphics in ways appropriate to the locales where your application will be used.
+</p>
+
+<p>This document describes best practices for localizing Android
+applications. The principles apply whether you are developing your application
+using ADT with Eclipse, Ant-based tools, or any other IDE. </p>
+
+<p>You should already have a working knowledge of Java and be  familiar with
+Android resource loading, the declaration of user interface elements in XML,
+development considerations such as Activity lifecycle, and general principles of
+internationalization and localization. </p>
+
+<p>It is good practice to use the Android resource framework to separate the
+localized aspects of your application as much as possible from the core Java
+functionality:</p>
+
+<ul>
+  <li>You can put most or all of the <em>contents</em> of your application's
+user interface into resource files, as described in this document and in <a
+href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a>.</li>
+  <li>The <em>behavior</em> of the user interface, on the other hand, is driven
+by your Java code.
+    For example, if users input data that needs to be formatted or sorted
+differently depending on locale, then you would use Java to handle the data
+programmatically. This document does not cover how to  localize your Java code.
+</li>
+</ul>
+
+<p>For a short guide to localizing strings in your app, see the training lesson, <a
+href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting Different Languages</a>. </p>
+
+
+<h2 id="resource-switching">Overview: Resource-Switching in Android</h2>
+
+<p>Resources are text strings, layouts, sounds, graphics, and any other static
+data that your  Android application  needs. An application can include multiple
+sets of resources, each customized for a different device configuration. When a
+user runs the application,  Android    automatically selects and loads the
+resources that best match the device.</p>
+
+<p>(This document focuses on localization and locale. For a complete description
+of resource-switching and all the types of configurations that you can
+specify &#8212; screen orientation, touchscreen type, and so on &#8212; see <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
+Alternative Resources</a>.)</p>
+
+<table border="0" cellspacing="0" cellpadding="0">
+  <tr border="0">
+    <td width="180" style="border: 0pt none ;"><p class="special-note">
+    <strong>When you write your application:</strong>
+    <br><br>
+    You create a set of default resources, plus alternatives to be used in
+    different locales.</p></td>
+    <td style="border: 0pt none; padding:0">
+    <p style="border:0; padding:0"><img src="../../../images/resources/right-arrow.png" alt="right-arrow"
+    width="51" height="17"></p></td>
+    <td width="180" style="border: 0pt none ;"><p class="special-note">
+    <strong>When a user runs your application:</strong>
+    <br><br>The Android system selects which resources to load, based on the
+    device's locale.</p></td>
+  </tr>
+</table>
+
+<p>When you write your application, you create default and alternative resources
+for your application to use. To create  resources, you place files within
+specially named subdirectories of the project's <code>res/</code> directory.
+</p>
+
+
+
+<h3 id="defaults-r-important">Why Default Resources Are Important</h3>
+
+<p>Whenever the application runs in a locale for which you have not provided
+locale-specific text,  Android will load the default strings from
+<code>res/values/strings.xml</code>. If this default  file is absent, or if it
+is missing a string that your application needs, then your application will not run
+and will show an error.
+The example below illustrates what can happen when the default text file is incomplete. </p>
+
+<p><em>Example:</em>
+<p>An application's Java code refers to just two strings, <code>text_a</code> and
+  <code>text_b</code>. This application includes a localized resource file
+  (<code>res/values-en/strings.xml</code>) that defines <code>text_a</code> and
+  <code>text_b</code> in English. This application also includes a default
+  resource file (<code>res/values/strings.xml</code>) that includes a
+definition for <code>text_a</code>, but not for <code>text_b</code>:
+<ul>
+  <li>This application might compile without a problem. An IDE such as Eclipse
+    will not highlight any errors if a resource is missing.</li>
+  <li>When this application is launched on a device with locale set to English,
+    the application  might run without a problem, because
+    <code>res/values-en/strings.xml</code> contains both of the needed text
+    strings.</li>
+  <li>However, <strong>the user  will see an error message and a Force Close
+    button</strong> when this application is launched on a device set to a
+    language other than English. The application will not load.</li>
+</ul>
+
+
+<p>To prevent this situation, make sure that a <code>res/values/strings.xml</code>
+  file exists and that it defines every needed string. The situation applies to
+  all types of resources, not just strings: You
+  need to create a  set of default resource files containing all
+  the resources that your application calls upon &#8212; layouts, drawables,
+  animations, etc. For information about testing, see <a href="#test-for-default">
+  Testing for Default Resources</a>.</p>
+
+<h2 id="using-framework">Using Resources for Localization</h2>
+
+<h3 id="creating-defaults">How to Create Default Resources</h3>
+
+<p>Put the application's default text in
+a file with the following location and name:</p>
+<p><code>&nbsp;&nbsp;&nbsp;&nbsp;res/values/strings.xml</code> (required directory)</p>
+
+<p>The text strings in <code>res/values/strings.xml</code> should  use the
+default language, which is the language that you expect most of your application's users to
+speak.  </p>
+
+<p>The default resource set must also include any default drawables and layouts,
+  and can include other types of resources such as animations.
+<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/drawable/</code>(required directory holding at least
+  one graphic file, for the application's icon on Google Play)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/layout/</code> (required directory holding an XML
+  file that defines the default layout)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/anim/</code> (required if you have any
+  <code>res/anim-<em>&lt;qualifiers&gt;</em></code> folders)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/xml/</code> (required if you have any
+  <code>res/xml-<em>&lt;qualifiers&gt;</em></code> folders)<br>
+  <code>&nbsp;&nbsp;&nbsp;&nbsp;res/raw/</code> (required if you have any
+  <code>res/raw-<em>&lt;qualifiers&gt;</em></code> folders)
+</p>
+
+<p class="note"><strong>Tip:</strong> In your code, examine each reference to
+  an Android resource. Make sure that a default resource is defined for each
+  one. Also make sure that the default string file is complete: A <em>
+  localized</em> string file can contain a subset of the strings, but the
+  <em>default</em> string file must contain them all.
+</p>
+
+<h3 id="creating-alternatives">How to Create Alternative Resources</h3>
+
+<p>A large part of localizing an application is providing alternative text for
+different languages. In some cases you will also provide alternative graphics,
+sounds, layouts, and other locale-specific resources. </p>
+
+<p>An application can specify many <code>res/<em>&lt;qualifiers&gt;</em>/</code>
+directories, each with different qualifiers. To create an alternative resource for
+a different locale, you use a qualifier that specifies a language or a
+language-region combination. (The name of a resource directory must conform
+to the naming scheme described in
+<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing
+Alternative Resources</a>,
+or else it will not compile.)</p>
+
+<p><em>Example:</em></p>
+
+<p>Suppose that your application's default language is English. Suppose also
+that you want to localize all the text in your application to French, and most
+of the text in your application (everything except the application's title) to
+Japanese. In this case, you could create three alternative <code>strings.xml</code>
+files, each stored in a locale-specific resource directory:</p>
+
+<ol>
+  <li><code>res/values/strings.xml</code><br>
+    Contains  English text for all  the strings that the application uses,
+including text for a string named <code>title</code>.</li>
+  <li><code>res/values-fr/strings.xml</code><br>
+    Contain French text for all  the strings, including <code>title</code>.</li>
+  <li><code>res/values-ja/strings.xml</code><br>
+    Contain Japanese text for all  the strings <em>except</em>
+<code>title</code>.<br>
+  <code></code></li>
+</ol>
+
+<p>If your Java code refers to <code>R.string.title</code>,  here is what will
+happen at runtime:</p>
+
+<ul>
+  <li>If the device is set to any language other than French, Android will load
+<code>title</code> from the <code>res/values/strings.xml</code> file.</li>
+  <li>If the device is set to French, Android will load <code>title</code> from
+the <code>res/values-fr/strings.xml</code> file.</li>
+</ul>
+
+<p>Notice that if the device is set to Japanese, Android will look for
+<code>title</code> in the <code>res/values-ja/strings.xml</code> file. But
+because no such string is included in that file, Android will fall back to the
+default, and will load  <code>title</code> in English from the
+<code>res/values/strings.xml</code> file.  </p>
+
+<h3 id="resource-precedence">Which Resources Take Precedence?</h3>
+
+<p> If multiple resource files match a device's configuration, Android follows a
+set of rules in deciding which file to use. Among the qualifiers that can be
+specified in a resource directory name, <strong>locale almost always takes
+precedence</strong>. </p>
+<p><em>Example:</em></p>
+
+<p>Assume that an application  includes a default set of graphics and two other
+sets of graphics, each optimized for a different device setup:</p>
+
+<ul>
+  <li><code>res/drawable/</code><br>
+    Contains
+  default graphics.</li>
+  <li><code>res/drawable-small-land-stylus/</code><br>
+  Contains  graphics optimized for use with a device that expects input from a
+  stylus and has a QVGA low-density screen in landscape orientation.</li>
+  <li><code>res/drawable-ja/</code> <br>
+  Contains  graphics optimized for use with Japanese.</li>
+</ul>
+
+<p>If the application runs on a device that is configured to use Japanese,
+Android will load graphics from  <code>res/drawable-ja/</code>, even if the
+device happens to be one that expects input from a stylus and has a QVGA
+low-density screen in landscape orientation.</p>
+
+<p class="note"><strong>Exception:</strong> The only qualifiers that take
+precedence over locale in the selection process are MCC and MNC (mobile country
+code and mobile network code). </p>
+
+<p><em>Example:</em></p>
+
+<p>Assume that you have the following situation:</p>
+
+<ul>
+  <li>The application code calls for <code>R.string.text_a</code></li>
+  <li>Two relevant resource files are available:
+    <ul>
+      <li><code>res/values-mcc404/strings.xml</code>, which includes
+<code>text_a</code> in the application's default language, in this case
+English.</li>
+      <li><code>res/values-hi/strings.xml</code>, which includes
+<code>text_a</code> in Hindi.</li>
+    </ul>
+  </li>
+  <li>The application is running on a device that has the following
+configuration:
+    <ul>
+      <li>The SIM card is connected to a mobile network in India (MCC 404).</li>
+      <li>The language is set to Hindi (<code>hi</code>).</li>
+    </ul>
+  </li>
+</ul>
+
+<p>Android will load <code>text_a</code> from
+<code>res/values-mcc404/strings.xml</code> (in English), even if the device is
+configured for Hindi. That is because in the resource-selection process, Android
+will prefer an MCC match over a language match. </p>
+
+<p>The selection process is not always as straightforward as these examples
+suggest. Please read  <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#BestMatch">How Android Finds
+the Best-matching Resource</a> for a more nuanced description of the
+process. All the qualifiers are described and listed in order of
+precedence in <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#table2">Table 2 of Providing
+Alternative Resources</a>.</p>
+
+<h3 id="referring-to-resources">Referring to Resources in Java</h3>
+
+<p>In your application's Java code, you refer to  resources using the syntax
+<code>R.<em>resource_type</em>.<em>resource_name</em></code> or
+<code>android.R.<em>resource_type</em>.<em>resource_name</em></code><em>.</em>
+For more about this, see <a
+href="{@docRoot}guide/topics/resources/accessing-resources.html">Accessing Resources</a>.</p>
+
+<h2 id="checklist">Localization Checklist</h2>
+
+<p>For a complete overview of the process of localizing and distributing an Android application,
+see the <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization
+Checklist</a> document.</p>
+
+<h2 id="strategies">Localization Tips</h2>
+
+<h4 id="failing2">Design your application  to work in any locale</h4>
+
+<p>You cannot assume anything about the device on which a user will
+run your application. The device might have hardware that you were not
+anticipating, or it might be set to a locale that you did not plan for or that
+you cannot test. Design your application so that it will function normally or fail gracefully no
+matter what device it runs on.</p>
+
+<p class="note"><strong>Important:</strong> Make sure that your application
+includes a full set of default resources.</p> <p>Make sure to include
+<code>res/drawable/</code> and a <code>res/values/</code> folders (without any
+additional modifiers in the folder names) that contain all the images and text
+that your application will need. </p>
+
+<p>If an application is missing even one default resource, it will not run on a
+  device that is set to an unsupported locale. For example, the
+  <code>res/values/strings.xml</code> default file might lack one string that
+  the application needs: When the application runs in an unsupported locale and
+  attempts to load <code>res/values/strings.xml</code>, the user will see an
+  error message and a Force Close button. An IDE such as Eclipse will not
+  highlight this kind of error, and you will not see the problem when you
+  test the application on a device or emulator that is set to a supported locale.</p>
+
+<p>For more information, see <a href="#test-for-default">Testing for Default Resources</a>.</p>
+
+<h4>Design a flexible layout</h4>
+
+<p> If you need to rearrange your layout to fit a certain language (for example
+German with its long words), you can create an alternative layout for that
+language (for example <code>res/layout-de/main.xml</code>). However, doing this
+can make your application harder to maintain.  It is better to create a single
+layout that is more flexible.</p>
+
+<p>Another typical situation is a language that requires something different in
+its layout. For example, you might have a contact form that should include  two
+name fields when the application runs in Japanese, but three name fields when
+the application  runs in some other language. You could handle this in either of
+two ways:</p>
+
+<ul>
+  <li>Create  one  layout with a field that you can programmatically enable or
+disable, based on the language, or</li>
+  <li>Have the main layout include another layout that  includes the changeable
+field. The second layout can have different configurations for different
+languages.</li>
+</ul>
+
+<h4>Avoid creating more resource files and text strings than you need</h4>
+
+<p>You probably do not need to create a locale-specific
+alternative for every resource in your application. For example, the layout
+defined in the <code>res/layout/main.xml</code> file might work in any locale,
+in which case there would be no need to create any alternative layout files.
+</p>
+
+<p>Also, you might not need to create alternative text for every
+string. For example, assume the following:</p>
+
+<ul>
+  <li>Your application's default language is American
+English. Every string that the application uses is defined, using American
+English spellings, in <code>res/values/strings.xml</code>. </li>
+
+  <li>For  a few important phrases, you want to provide
+British English spelling. You want these alternative strings to be used when your
+application runs on a device in the United Kingdom. </li>
+</ul>
+
+<p>To do this, you could create a small file called
+<code>res/values-en-rGB/strings.xml</code> that includes only the strings that
+should be different when the application  runs in the U.K. For all the rest of
+the strings, the application will fall back to the defaults and use what is
+defined in <code>res/values/strings.xml</code>.</p>
+
+<h4>Use the Android Context object for manual locale lookup</h4>
+
+<p>You can look up the locale using the {@link android.content.Context} object
+that Android makes available:</p>
+
+<pre>String locale = context.getResources().getConfiguration().locale.getDisplayName();</pre>
+
+<h2 id="testing">Testing Localized Applications</h2>
+
+<h3 id="device">Testing on a Device</h3>
+<p>Keep in mind that the device you are testing may be significantly different from
+  the devices available to consumers in other geographies. The locales available
+  on your device may differ from those available on other devices. Also, the
+  resolution and density of the device screen may differ, which could affect
+  the display of strings and drawables in your UI.</p>
+
+<p>To change the locale on a device, use  the Settings application  (Home &gt;
+Menu &gt; Settings &gt; Locale &amp; text &gt; Select locale). </p>
+
+<h3 id="emulator">Testing on an Emulator</h3>
+
+<p>For details about using the emulator, see See <a
+href="{@docRoot}tools/help/emulator.html">Android Emulator</a>.</p>
+<h4>Creating and using a custom locale</h4>
+
+<p>A &quot;custom&quot; locale is a language/region combination that the Android
+system image does not explicitly support. (For a list of supported locales in
+Android platforms see the Version Notes in the <a
+href="{@docRoot}sdk/index.html">SDK</a> tab). You can test
+how your application will run in a custom locale by creating a custom locale in
+the emulator. There are two ways to do this:</p>
+
+<ul>
+  <li>Use the Custom Locale application, which is accessible from the
+Application tab. (After you create a custom locale, switch to it by
+pressing and holding the locale name.)</li>
+  <li>Change to a custom locale from the adb shell, as described below.</li>
+</ul>
+
+<p>When you set the emulator to a locale that is not available in the Android
+system image, the system itself will display in its default language. Your
+application, however, should localize properly.</p>
+
+<h4>Changing the emulator locale from the adb shell</h4>
+
+<p>To change the locale in the emulator by using the adb shell. </p>
+
+<ol>
+  <li>Pick the locale you want to test and determine its language and region codes, for
+example <code>fr</code> for French and <code>CA</code> for Canada.<br>
+  </li>
+  <li>Launch an emulator.</li>
+  <li>From a command-line shell on the host computer, run the following
+command:<br>
+    <code>adb shell</code><br>
+  or if you have a device attached, specify that you want the emulator by adding
+the <code>-e</code> option:<br>
+  <code>adb -e shell</code></li>
+  <li>At  the  adb shell prompt (<code>#</code>), run this command: <br>
+    <code>setprop persist.sys.language  [<em>language code</em>];setprop
+persist.sys.country [<em>country  code</em>];stop;sleep 5;start <br>
+    </code>Replace bracketed sections with the  appropriate codes from Step
+1.</li>
+</ol>
+
+<p>For instance, to test in Canadian French:</p>
+
+<p><code>setprop persist.sys.language  fr;setprop persist.sys.country
+CA;stop;sleep 5;start </code></p>
+
+<p>This will cause the emulator  to restart. (It will look like a full reboot,
+but it is not.) Once the Home screen appears again, re-launch your application (for
+example, click the Run icon in Eclipse), and the application will launch with
+the new locale. </p>
+
+<h3 id="test-for-default">Testing for Default Resources</h3>
+<p>Here's how to test whether an application includes every string resource that it needs:  </p>
+<ol><li>Set the emulator or device to a language that your application does not
+  support. For example, if the application has French strings in
+  <code>res/values-fr/</code> but does not have any Spanish strings in
+  <code>res/values-es/</code>, then set the emulator's locale to Spanish.
+  (You can use the Custom Locale application to set the emulator to an
+  unsupported locale.)</li>
+  <li>Run the application.</li>
+<li>If the application shows an error message and a Force Close button, it might
+  be looking for a string that is not available. Make sure that your
+  <code>res/values/strings.xml</code> file includes a definition for
+  every string that the application uses.</li>
+</ol>
+</p>
+
+<p>If the test is successful, repeat it for other types of
+  configurations. For example, if the application has a layout file called
+  <code>res/layout-land/main.xml</code> but does not contain a file called
+  <code>res/layout-port/main.xml</code>, then set the emulator or device to
+  portrait orientation and see if the application will run.
+
diff --git a/docs/html/guide/topics/resources/runtime-changes.jd b/docs/html/guide/topics/resources/runtime-changes.jd
index 45a548a..695647b 100644
--- a/docs/html/guide/topics/resources/runtime-changes.jd
+++ b/docs/html/guide/topics/resources/runtime-changes.jd
@@ -1,5 +1,5 @@
 page.title=Handling Runtime Changes
-page.tags="activity","lifecycle"
+page.tags=activity,lifecycle
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/search/adding-custom-suggestions.jd b/docs/html/guide/topics/search/adding-custom-suggestions.jd
index 47ad2fe..6ebef08 100644
--- a/docs/html/guide/topics/search/adding-custom-suggestions.jd
+++ b/docs/html/guide/topics/search/adding-custom-suggestions.jd
@@ -1,5 +1,5 @@
 page.title=Adding Custom Suggestions
-page.tags="SearchRecentSuggestionsProvider",
+page.tags=SearchRecentSuggestionsProvider,
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
index c1d59d4..e1020dd 100644
--- a/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
+++ b/docs/html/guide/topics/search/adding-recent-query-suggestions.jd
@@ -1,5 +1,5 @@
 page.title=Adding Recent Query Suggestions
-page.tags="SearchRecentSuggestions","SearchRecentSuggestionsProvider"
+page.tags=SearchRecentSuggestions,SearchRecentSuggestionsProvider
 
 @jd:body
 
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index fc722b2..fcaaed36 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -1,5 +1,5 @@
 page.title=Creating a Search Interface
-page.tags="searchview"
+page.tags=searchview
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/sensors/index.jd b/docs/html/guide/topics/sensors/index.jd
index 65560e6..09d27e7 100644
--- a/docs/html/guide/topics/sensors/index.jd
+++ b/docs/html/guide/topics/sensors/index.jd
@@ -1,6 +1,6 @@
 page.title=Location and Sensors APIs
 page.landing=true
-page.tags="location","sensors"
+page.tags=location,sensors
 page.landing.intro=Use sensors on the device to add rich location and motion capabilities to your app, from GPS or network location to accelerometer, gyroscope, temperature, barometer, and more. 
 page.landing.image=
 
@@ -38,4 +38,4 @@
     </a>
   </div>
 
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/guide/topics/sensors/sensors_motion.jd b/docs/html/guide/topics/sensors/sensors_motion.jd
index 289c639..99b689f 100644
--- a/docs/html/guide/topics/sensors/sensors_motion.jd
+++ b/docs/html/guide/topics/sensors/sensors_motion.jd
@@ -1,5 +1,5 @@
 page.title=Motion Sensors
-page.tags="sensorevent","accelerometer","gyroscope","gravity","rotation"
+page.tags=sensorevent,accelerometer,gyroscope,gravity,rotation
 @jd:body
 
 <div id="qv-wrapper">
@@ -450,4 +450,4 @@
 <p>The Android SDK provides a sample application that shows how to use the rotation vector sensor.
 The sample application is located in the API Demos code (<a
 href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/os/RotationVectorDemo.html">
-OS - RotationVectorDemo</a>).</p>
\ No newline at end of file
+OS - RotationVectorDemo</a>).</p>
diff --git a/docs/html/guide/topics/sensors/sensors_position.jd b/docs/html/guide/topics/sensors/sensors_position.jd
index 55b282b..65b9350 100644
--- a/docs/html/guide/topics/sensors/sensors_position.jd
+++ b/docs/html/guide/topics/sensors/sensors_position.jd
@@ -1,5 +1,5 @@
 page.title=Position Sensors
-page.tags="sensorevent","orientation","proximity"
+page.tags=sensorevent,orientation,proximity
 @jd:body
 
 <div id="qv-wrapper">
@@ -313,4 +313,4 @@
 "near" or "far." In this case, the sensor usually reports its maximum range value in the far state
 and a lesser value in the near state. Typically, the far value is a value > 5 cm, but this can vary
 from sensor to sensor. You can determine a sensor's maximum range by using the {@link
-android.hardware.Sensor#getMaximumRange} method.</p>
\ No newline at end of file
+android.hardware.Sensor#getMaximumRange} method.</p>
diff --git a/docs/html/guide/topics/text/copy-paste.jd b/docs/html/guide/topics/text/copy-paste.jd
index b34f0fa..8f898e4 100644
--- a/docs/html/guide/topics/text/copy-paste.jd
+++ b/docs/html/guide/topics/text/copy-paste.jd
@@ -1,5 +1,5 @@
 page.title=Copy and Paste
-page.tags="clipboardmanager","clipdata","input"
+page.tags=clipboardmanager,clipdata,input
 @jd:body
 <div id="qv-wrapper">
     <div id="qv">
diff --git a/docs/html/guide/topics/text/creating-input-method.jd b/docs/html/guide/topics/text/creating-input-method.jd
index 7254594..205fd96 100644
--- a/docs/html/guide/topics/text/creating-input-method.jd
+++ b/docs/html/guide/topics/text/creating-input-method.jd
@@ -1,5 +1,5 @@
 page.title=Creating an Input Method
-page.tags="ime","keyboard","inputmethodservice"
+page.tags=ime,keyboard,inputmethodservice
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/text/spell-checker-framework.jd b/docs/html/guide/topics/text/spell-checker-framework.jd
index 366f9cc..a5d9932 100644
--- a/docs/html/guide/topics/text/spell-checker-framework.jd
+++ b/docs/html/guide/topics/text/spell-checker-framework.jd
@@ -1,5 +1,5 @@
 page.title=Spelling Checker Framework
-page.tags="input","spellcheckerservice"
+page.tags=input,spellcheckerservice
 @jd:body
 <div id="qv-wrapper">
 <div id="qv">
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 3173ff1..a122443 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1,5 +1,5 @@
 page.title=Action Bar
-page.tags="actionbar","menu","tabs"
+page.tags=actionbar,menu,tabs
 
 @jd:body
 
diff --git a/docs/html/guide/topics/ui/controls/button.jd b/docs/html/guide/topics/ui/controls/button.jd
index 41b67b7f..02597c8 100644
--- a/docs/html/guide/topics/ui/controls/button.jd
+++ b/docs/html/guide/topics/ui/controls/button.jd
@@ -1,5 +1,5 @@
 page.title=Buttons
-page.tags="button","imagebutton"
+page.tags=button,imagebutton
 @jd:body
 
 <div id="qv-wrapper">
@@ -241,4 +241,4 @@
   <p>For more information about this XML syntax, including how to define a disabled, hovered, or
 other button states, read about <a
 href="{@docRoot}guide/topics/resources/drawable-resource.html#StateList">State List
-Drawable</a>.</p>
\ No newline at end of file
+Drawable</a>.</p>
diff --git a/docs/html/guide/topics/ui/controls/pickers.jd b/docs/html/guide/topics/ui/controls/pickers.jd
index 4c55840..31e4d3f5 100644
--- a/docs/html/guide/topics/ui/controls/pickers.jd
+++ b/docs/html/guide/topics/ui/controls/pickers.jd
@@ -1,5 +1,5 @@
 page.title=Pickers
-page.tags="datepicker","timepicker"
+page.tags=datepicker,timepicker
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/controls/radiobutton.jd b/docs/html/guide/topics/ui/controls/radiobutton.jd
index d0c48ed..b2556e19 100644
--- a/docs/html/guide/topics/ui/controls/radiobutton.jd
+++ b/docs/html/guide/topics/ui/controls/radiobutton.jd
@@ -1,5 +1,5 @@
 page.title=Radio Buttons
-page.tags="radiobutton","radiogroup"
+page.tags=radiobutton,radiogroup
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/controls/spinner.jd b/docs/html/guide/topics/ui/controls/spinner.jd
index 85714b6..d2db7a4 100644
--- a/docs/html/guide/topics/ui/controls/spinner.jd
+++ b/docs/html/guide/topics/ui/controls/spinner.jd
@@ -1,5 +1,5 @@
 page.title=Spinners
-page.tags="adapterview","spinneradapter"
+page.tags=adapterview,spinneradapter
 @jd:body
 
 <div id="qv-wrapper">
@@ -143,4 +143,4 @@
 <p>If you implement the {@link
 android.widget.AdapterView.OnItemSelectedListener} interface with your {@link
 android.app.Activity} or {@link android.app.Fragment} (such as in the example above), you can pass
-<code>this</code> as the interface instance.</p>
\ No newline at end of file
+<code>this</code> as the interface instance.</p>
diff --git a/docs/html/guide/topics/ui/controls/text.jd b/docs/html/guide/topics/ui/controls/text.jd
index c0b9873..9474dee 100644
--- a/docs/html/guide/topics/ui/controls/text.jd
+++ b/docs/html/guide/topics/ui/controls/text.jd
@@ -1,5 +1,5 @@
 page.title=Text Fields
-page.tags="edittext","autocompletetextview"
+page.tags=edittext,autocompletetextview
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/controls/togglebutton.jd b/docs/html/guide/topics/ui/controls/togglebutton.jd
index 3119cd9..c57b510 100644
--- a/docs/html/guide/topics/ui/controls/togglebutton.jd
+++ b/docs/html/guide/topics/ui/controls/togglebutton.jd
@@ -1,5 +1,5 @@
 page.title=Toggle Buttons
-page.tags="switch","togglebutton"
+page.tags=switch,togglebutton
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/custom-components.jd b/docs/html/guide/topics/ui/custom-components.jd
index 703a5ce..b146098 100644
--- a/docs/html/guide/topics/ui/custom-components.jd
+++ b/docs/html/guide/topics/ui/custom-components.jd
@@ -1,5 +1,5 @@
 page.title=Custom Components
-page.tags="view","widget"
+page.tags=view,widget
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index 6586c2f..616949b 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -1,5 +1,5 @@
 page.title=Layouts
-page.tags="view","viewgroup"
+page.tags=view,viewgroup
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index d934c4b..4754d11 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -1,5 +1,5 @@
 page.title=Dialogs
-page.tags="alertdialog","dialogfragment"
+page.tags=alertdialog,dialogfragment
 
 @jd:body
 
diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
index 9a6b0e9..9d8aa9b 100644
--- a/docs/html/guide/topics/ui/drag-drop.jd
+++ b/docs/html/guide/topics/ui/drag-drop.jd
@@ -1,5 +1,5 @@
 page.title=Drag and Drop
-page.tags="clipdata","dragevent","onlongclicklistener"
+page.tags=clipdata,dragevent,onlongclicklistener
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/layout/gridview.jd b/docs/html/guide/topics/ui/layout/gridview.jd
index bc189c4..b8d24b60 100644
--- a/docs/html/guide/topics/ui/layout/gridview.jd
+++ b/docs/html/guide/topics/ui/layout/gridview.jd
@@ -1,5 +1,5 @@
 page.title=Grid View
-page.tags="gridview"
+page.tags=gridview
 @jd:body
 <div id="qv-wrapper">
 <div id="qv">
diff --git a/docs/html/guide/topics/ui/layout/linear.jd b/docs/html/guide/topics/ui/layout/linear.jd
index 444dc71..902f22f 100644
--- a/docs/html/guide/topics/ui/layout/linear.jd
+++ b/docs/html/guide/topics/ui/layout/linear.jd
@@ -1,5 +1,5 @@
 page.title=Linear Layout
-page.tags="linearlayout"
+page.tags=linearlayout
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/ui/layout/listview.jd b/docs/html/guide/topics/ui/layout/listview.jd
index f8315c5..3c6e32c 100644
--- a/docs/html/guide/topics/ui/layout/listview.jd
+++ b/docs/html/guide/topics/ui/layout/listview.jd
@@ -1,5 +1,5 @@
 page.title=List View
-page.tags="listview"
+page.tags=listview
 @jd:body
 <div id="qv-wrapper">
 <div id="qv">
diff --git a/docs/html/guide/topics/ui/layout/relative.jd b/docs/html/guide/topics/ui/layout/relative.jd
index 65c5617..69f5c0a 100644
--- a/docs/html/guide/topics/ui/layout/relative.jd
+++ b/docs/html/guide/topics/ui/layout/relative.jd
@@ -1,5 +1,5 @@
 page.title=Relative Layout
-page.tags="relativelayout"
+page.tags=relativelayout
 @jd:body
 
 <div id="qv-wrapper">
@@ -114,4 +114,4 @@
 </pre>
 
 <p>For details about all the layout attributes available to each child view of a {@link
-android.widget.RelativeLayout}, see {@link android.widget.RelativeLayout.LayoutParams}.</p>
\ No newline at end of file
+android.widget.RelativeLayout}, see {@link android.widget.RelativeLayout.LayoutParams}.</p>
diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
index d96447d..1d36430 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -1,5 +1,5 @@
 page.title=Settings
-page.tags="preference","preferenceactivity","preferencefragment"
+page.tags=preference,preferenceactivity,preferencefragment
 
 @jd:body
 
diff --git a/docs/html/guide/webapps/best-practices.jd b/docs/html/guide/webapps/best-practices.jd
index 1362990..a13c69da 100644
--- a/docs/html/guide/webapps/best-practices.jd
+++ b/docs/html/guide/webapps/best-practices.jd
@@ -1,6 +1,24 @@
 page.title=Best Practices for Web Apps
 @jd:body
 
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>See also</h2>
+<ul>
+  <li><a href="https://developers.google.com/chrome/mobile/docs/webview/pixelperfect"
+  >Pixel-Perfect UI in the WebView</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/responsivedesign/" class="external-link">Creating
+  a Mobile-First Responsive Web Design</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/high-dpi/" class="external-link">High
+  DPI Images for Variable Pixel Densities</a></li>
+</ul>
+
+</div>
+</div>
+
+
+
 <style>
 .bold li {
   font-weight:bold;
diff --git a/docs/html/guide/webapps/debugging.jd b/docs/html/guide/webapps/debugging.jd
index 1eef1ae..3c95fc2 100644
--- a/docs/html/guide/webapps/debugging.jd
+++ b/docs/html/guide/webapps/debugging.jd
@@ -18,19 +18,29 @@
 
 <h2>See also</h2>
 <ol>
+  <li><a class="external-link"
+href="https://developers.google.com/chrome-developer-tools/docs/remote-debugging">Remote
+Debugging on Android</a></li>
   <li><a href="{@docRoot}tools/debugging/index.html">Debugging</a></li>
 </ol>
 
 </div>
 </div>
 
-<p>If you're developing a web application for Android, you can debug your JavaScript
-using the {@code console} JavaScript APIs, which output messages to logcat. If you're familiar with
+<p>If you are testing your web app with a device running Android 4.4 or higher,
+you can remotely debug your web pages in {@link android.webkit.WebView} with
+Chrome Developer Tools, while continuing to support older versions of Android.
+For more information, see <a class="external-link"
+href="https://developers.google.com/chrome-developer-tools/docs/remote-debugging">Remote
+Debugging on Android</a>.</p>
+
+<p>If you don't have a device running Android 4.4 or higher, you can debug your JavaScript using the
+{@code console} JavaScript APIs and view the output messages to logcat. If you're familiar with
 debugging web pages with Firebug or Web Inspector, then you're probably familiar
 with using {@code console} (such as {@code console.log()}). Android's WebKit framework supports most
 of the same APIs, so you can receive logs from your web page when debugging in Android's Browser
-or in your own {@link android.webkit.WebView}.</p>
-
+or in your own {@link android.webkit.WebView}. This document describes how to use the
+console APIs for debugging.</p>
 
 
 <h2 id="Browser">Using Console APIs in the Android Browser</h2>
@@ -83,28 +93,17 @@
 
 <h2 id="WebView">Using Console APIs in WebView</h2>
 
-<p>If you've implemented a custom {@link android.webkit.WebView} in your application, all the
-same console APIs are supported when debugging your web page in WebView. On Android
-1.6 and lower, console messages are automatically sent to logcat with the
-"WebCore" logging tag. If you're targeting Android 2.1 (API Level 7) or higher, then you must
+<p>All the console APIs shown above are also
+supported when debugging in {@link android.webkit.WebView}. 
+If you're targeting Android 2.1 (API level 7) and higher, you must
 provide a {@link android.webkit.WebChromeClient}
 that implements the {@link android.webkit.WebChromeClient#onConsoleMessage(String,int,String)
-onConsoleMessage()} callback method, in order for console messages to appear in logcat.</p>
-
-<p>Additionally, the {@link
-android.webkit.WebChromeClient#onConsoleMessage(String,int,String)} method introduced in API
-Level 7 has been deprecated in favor of {@link
-android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)} in API Level 8.</p>
-
-<p>Whether you're developing for Android 2.1 (API Level 7) or Android 2.2 (API Level 8 or
-greater), you must implement {@link android.webkit.WebChromeClient} and override the appropriate
-{@link
-android.webkit.WebChromeClient#onConsoleMessage(String,int,String) onConsoleMessage()} callback
-method. Then, apply the {@link android.webkit.WebChromeClient} to your {@link
+onConsoleMessage()} method in order for console messages to appear in logcat.
+Then, apply the {@link android.webkit.WebChromeClient} to your {@link
 android.webkit.WebView} with {@link android.webkit.WebView#setWebChromeClient(WebChromeClient)
 setWebChromeClient()}.
 
-<p>Using API Level 7, this is how your code for {@link
+<p>For example, to support API level 7, this is how your code for {@link
 android.webkit.WebChromeClient#onConsoleMessage(String,int,String)} might look:</p>
 
 <pre>
@@ -118,8 +117,8 @@
 });
 </pre>
 
-<p>With API Level 8 or greater, your code for {@link
-android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)} might look like this:</p>
+<p>However, if your lowest supported version is API level 8 or higher, you should instead
+implement {@link android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)}. For example:</p>
 
 <pre>
 WebView myWebView = (WebView) findViewById(R.id.webview);
@@ -134,8 +133,8 @@
 </pre>
 
 <p>The {@link android.webkit.ConsoleMessage} also includes a {@link
-android.webkit.ConsoleMessage.MessageLevel MessageLevel} to indicate the type of console message
-being delivered. You can query the message level with {@link
+android.webkit.ConsoleMessage.MessageLevel MessageLevel} object to indicate the type of console
+message being delivered. You can query the message level with {@link
 android.webkit.ConsoleMessage#messageLevel()} to determine the severity of the message, then
 use the appropriate {@link android.util.Log} method or take other appropriate actions.</p>
 
diff --git a/docs/html/guide/webapps/index.jd b/docs/html/guide/webapps/index.jd
index df7ddbe..a188d2b 100644
--- a/docs/html/guide/webapps/index.jd
+++ b/docs/html/guide/webapps/index.jd
@@ -1,16 +1,50 @@
 page.title=Web Apps
-page.landing=true
-page.landing.intro=Android has always been about connectivity and providing a great web browsing experience, so building your app with web technologies can be a great opportunity. Not only can you build an app on the web and still optimize your designs for Android's various screen sizes and densities, but you can also embed web-based content into your Android app using WebView.
-page.landing.image=
 
 @jd:body
 
-<div class="landing-docs">
+<div class="figure" style="width:327px">
+  <img src="{@docRoot}images/webapps/webapps.png" alt="" />
+  <p class="img-caption"><strong>Figure 1.</strong> You can make your web content available to
+users in two ways: in a traditional web browser and in an Android application, by
+including a WebView in the layout.</p>
+</div>
 
-  <div class="col-6">
-  </div>
+<p>There are essentially two ways to deliver an application on Android: as a
+client-side application (developed using the Android SDK and installed on user devices in an APK)
+or as a web application (developed using web standards and accessed through a web
+browser&mdash;there's nothing to install on user devices).</p>
 
-  <div class="col-6">
-  </div>
+<p>If you chose to provide a web-based app for Android-powered devices, you can rest
+assured that major web browsers for Android (and the {@link android.webkit.WebView} framework)
+allow you to specify viewport and style properties that make your web pages appear at the proper
+size and scale on all screen configurations.</p>
 
-</div>
\ No newline at end of file
+<p>Figure 1 illustrates how you can provide access to your web pages from either
+a web browser or your your own Android app. However, you shouldn't develop an Android
+app simply as a means to view your web site. Rather, the web pages you embed in your
+Android app should be designed especially for that environment. You can even define an
+interface between your Android application and your web pages that allows JavaScript in the web
+pages to call upon APIs in your Android application&mdash;providing Android APIs to your web-based
+application.</p>
+
+<p>To start developing web pages for Android-powered devices, see the following documents:</p>
+
+<dl>
+  <dt><a href="{@docRoot}guide/webapps/targeting.html"><strong>Supporting Different Screens from Web
+  Apps</strong></a></dt>
+  <dd>How to properly size your web app on Android-powered devices and support
+multiple screen densities. The information in this document is important if you're building a web
+application that you at least expect to be available on Android-powered devices (which you should
+assume for anything you publish on the web), but especially if you're targeting mobile devices
+or using {@link android.webkit.WebView}.</dd>
+  <dt><a href="{@docRoot}guide/webapps/webview.html"><strong>Building Web Apps in
+WebView</strong></a></dt>
+  <dd>How to embed web pages into your Android application using {@link
+  android.webkit.WebView} and bind JavaScript to Android APIs.</dd>
+  <dt><a href="{@docRoot}guide/webapps/debugging.html"><strong>Debugging Web Apps</strong></a></dt>
+  <dd>How to debug web apps using JavaScript Console APIs.</dd>
+  <dt><a href="{@docRoot}guide/webapps/best-practices.html"><strong>Best Practices for Web
+Apps</strong></a></dt>
+  <dd>A list of practices you should follow, in order to provide an effective web application on
+Android-powered devices.</dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/guide/webapps/overview.jd b/docs/html/guide/webapps/overview.jd
deleted file mode 100644
index 069290a..0000000
--- a/docs/html/guide/webapps/overview.jd
+++ /dev/null
@@ -1,71 +0,0 @@
-page.title=Web Apps Overview
-@jd:body
-
-<div class="figure" style="width:327px">
-  <img src="{@docRoot}images/webapps/webapps.png" alt="" />
-  <p class="img-caption"><strong>Figure 1.</strong> You can make your web content available to
-users in two ways: in a traditional web browser and in an Android application, by
-including a WebView in the layout.</p>
-</div>
-
-<p>There are essentially two ways to deliver an application on Android: as a
-client-side application (developed using the Android SDK and installed on user devices as an {@code
-.apk}) or as a web application (developed using web standards and accessed through a web
-browser&mdash;there's nothing to install on user devices).</p>
-
-<p>The approach you choose for your application could depend on several factors, but Android makes
-the decision to develop a web application easier by providing:</p>
-<ul>
-  <li>Support for viewport properties that allow you to properly size your web application
-based on the screen size</li>
-  <li>CSS and JavaScript features that allow you to provide different styles and images
-based on the screen's pixel density (screen resolution)</li>
-</ul>
-
-<p>Thus, your decision to develop a web application for Android can exclude consideration for
-screen support, because it's already easy to make your web pages look good on all types of screens
-powered by Android.</p>
-
-<p>Another great feature of Android is that you don't have to build your application purely on
-the client or purely on the web. You can mix the two together by developing a client-side Android
-application that embeds some web pages (using a {@link android.webkit.WebView} in your Android
-application layout). Figure 1 visualizes how you can provide access to your web pages from either
-a web browser or your Android application. However, you shouldn't develop an Android
-application simply as a means to launch your web site. Rather, the web pages you embed in your
-Android application should be designed especially for that environment. You can even define an
-interface between your Android application and your web pages that allows JavaScript in the web
-pages to call upon APIs in your Android application&mdash;providing Android APIs to your web-based
-application.</p>
-
-<p>Since Android 1.0, {@link android.webkit.WebView} has been available for Android
-applications to embed web content in their layout and bind JavaScript to Android APIs. After
-Android added support for more screen densities (adding support for high and low-density
-screens), Android 2.0 added features to the WebKit framework to allow web pages to specify
-viewport properties and query the screen density in order to modify styles
-and image assets, as mentioned above. Because these features are a part of Android's WebKit
-framework, both the Android Browser (the default web browser provided with the platform) and
-{@link android.webkit.WebView} support the same viewport and screen density features.</p>
-
-<p>To develop a web application for Android-powered devices, you should read the
-following documents:</p>
-
-<dl>
-  <dt><a href="{@docRoot}guide/webapps/targeting.html"><strong>Targeting Screens from Web
-Apps</strong></a></dt>
-  <dd>How to properly size your web app on Android-powered devices and support
-multiple screen densities. The information in this document is important if you're building a web
-application that you at least expect to be available on Android-powered devices (which you should
-assume for anything you publish on the web), but especially if you're targeting mobile devices
-or using {@link android.webkit.WebView}.</dd>
-  <dt><a href="{@docRoot}guide/webapps/webview.html"><strong>Building Web Apps in
-WebView</strong></a></dt>
-  <dd>How to embed web pages into your Android application using {@link android.webkit.WebView} and
-bind JavaScript to Android APIs.</dd>
-  <dt><a href="{@docRoot}guide/webapps/debugging.html"><strong>Debugging Web Apps</strong></a></dt>
-  <dd>How to debug web apps using JavaScript Console APIs.</dd>
-  <dt><a href="{@docRoot}guide/webapps/best-practices.html"><strong>Best Practices for Web
-Apps</strong></a></dt>
-  <dd>A list of practices you should follow, in order to provide an effective web application on
-Android-powered devices.</dd>
-</dl>
-
diff --git a/docs/html/guide/webapps/targeting.jd b/docs/html/guide/webapps/targeting.jd
index 7410202..7e02340 100644
--- a/docs/html/guide/webapps/targeting.jd
+++ b/docs/html/guide/webapps/targeting.jd
@@ -1,16 +1,8 @@
-page.title=Targeting Screens from Web Apps
+page.title=Supporting Different Screens in Web Apps
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Quickview</h2>
-<ul>
-  <li>You can target your web page for different screens using viewport metadata, CSS, and
-JavaScript</li>
-  <li>Techniques in this document work for Android 2.0 and greater, and for web pages rendered
-in the default Android Browser and in a {@link android.webkit.WebView}</li>
-</ul>
-
 <h2>In this document</h2>
 <ol>
 <li><a href="#Metadata">Using Viewport Metadata</a>
@@ -24,78 +16,88 @@
 <li><a href="#DensityJS">targeting Device Density with JavaScript</a></li>
 </ol>
 
+<h2>See also</h2>
+<ul>
+  <li><a href="https://developers.google.com/chrome/mobile/docs/webview/pixelperfect"
+  >Pixel-Perfect UI in the WebView</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/responsivedesign/" class="external-link">Creating
+  a Mobile-First Responsive Web Design</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/high-dpi/" class="external-link">High
+  DPI Images for Variable Pixel Densities</a></li>
+</ul>
+
 </div>
 </div>
 
 
-<p>If you're developing a web application for Android or redesigning one for mobile devices, you
-should carefully consider how your web pages appear on different kinds of screens. Because
-Android is available on devices with different types of screens, you should account for some factors
-that affect the way your web pages appear on Android devices.</p>
+<p>Because Android is available on devices with a variety of screen sizes and pixel densities, you
+should account for these factors in your web design so your web pages always appear at the
+appropriate size.</p>
 
-<p class="note"><strong>Note:</strong> The features described in this document are supported
-by the Android Browser application (provided with the default Android platform) and {@link
-android.webkit.WebView} (the framework view widget for displaying web pages), on Android 2.0 and
-greater. Third-party web browsers running on Android might not support these features for
-controlling the viewport size and screen densities.</p>
 
-<p>When targeting your web pages for Android devices, there are two fundamental factors that you
+<p>When targeting your web pages for Android devices, there are two major factors that you
 should account for:</p>
 
 <dl>
-  <dt>The size of the viewport and scale of the web page</dt>
-    <dd>When the Android Browser loads a web page, the default behavior is to load the
-page in "overview mode," which provides a zoomed-out perspective of the web page. You can override
-this behavior for your web page by defining the default dimensions of the viewport or the initial
-scale of the viewport. You can also control how much the user can zoom in and out of your web
-page, if at all. The user can also disable overview mode in the
-Browser settings, so you should never assume that your page will load in overview mode. You
-should instead customize the viewport size and/or scale as appropriate for your page.</p>
-    <p>However, when your page is rendered in a {@link android.webkit.WebView}, the page loads at
-full zoom (not in "overview mode"). That is, it appears at the default size for the page,
-instead of zoomed out. (This is also how the page appears if the user disables overview
-mode.)</p></dd>
+  <dt><a href="#Viewport">The viewport</a></dt>
+    <dd>The viewport is the rectangular area that provides a drawable region for your web page.
+    You can specify several viewport properties, such as its size and initial scale. Most important
+    is the view port width, which defines the total number of horizontal pixels available from the web page's point of
+    view (the number of CSS pixels available).
+   </dd>
 
-  <dt>The device's screen density</dt>
-    <dd>The screen density (the number of pixels per inch) on an Android-powered device affects
-the resolution and size at which a web page is displayed. (There are three screen density
-categories: low, medium, and high.) The Android Browser and {@link android.webkit.WebView}
-compensate for variations in the screen
-density by scaling a web page so that all devices display the web page at the same perceivable size
-as a medium-density screen. If graphics are an important element of your web design, you
-should pay close attention to the scaling that occurs on different densities, because image scaling
-can produce artifacts (blurring and pixelation).
-      <p>To provide the best visual representation on all
-screen densities, you should control how scaling occurs by providing viewport metadata about
-your web page's target screen density and providing alternative graphics for different screen
-densities, which you can apply to different screens using CSS or JavaScript.</p></dd>
+  <dt><a href="#DensityCSS">The screen density</a></dt>
+<dd>The {@link android.webkit.WebView} class and most web browsers on Android convert your CSS
+pixel values to density-independent pixel values, so your web page appears at the same perceivable
+size as a medium-density screen (about 160dpi). However, if graphics are an important element of
+your web design, you should pay close attention to the scaling that occurs on different densities,
+because a 300px-wide image on a 320dpi screen will be scaled up (using more physical pixels per CSS
+pixel), which can produce artifacts (blurring and pixelation).</dd>
+
 </dl>
 
-<p>The rest of this document describes how you can account for these effects and provide a good
-design on multiple types of screens.</p>
 
 
 
-<h2 id="Metadata">Using Viewport Metadata</h2>
 
-<p>The viewport is the area in which your web page is drawn. Although the viewport's visible area
-matches the size of the screen,
-the viewport has its own dimensions that determine the number of pixels available to a web page.
-That is, the number of pixels available to a web page before it exceeds the screen area is
-defined by the dimensions of the viewport,
-not the dimensions of the device screen. For example, although a device screen might have a width of
-480 pixels, the viewport can have a width of 800 pixels, so that a web page designed to be 800
-pixels wide is completely visible on the screen.</p>
+<h2 id="Viewport">Specifying Viewport Properties</h2>
 
-<p>You can define properties of the viewport for your web page using the {@code "viewport"}
-property in an HTML {@code &lt;meta&gt;} tag (which must
-be placed in your document {@code &lt;head&gt;}). You can define multiple viewport properties in the
-{@code &lt;meta&gt;} tag's {@code content} attribute. For example, you can define the height and
-width of the viewport, the initial scale of the page, and the target screen density.
-Each viewport property in the {@code content} attribute must be separated by a comma.</p>
+<p>The viewport is the area in which your web page is drawn. Although the viewport's total visible
+area matches the size of the screen when zoomed all the way out, the viewport has its own pixel
+dimensions that it makes available to a web page. For example, although a device screen might
+have physical a width
+of 480 pixels, the viewport can have a width of 800 pixels. This allows a web page designed at 800
+pixels wide to be completely visible on the screen when the viewport scale is 1.0. Most web browsers on
+Android (including Chrome) set the viewport to a large size by default (known as "wide viewport
+mode" at about 980px wide). Many browsers also zoom out as far as possible, by default, to
+show the full viewport width (known as "overview mode").</p>
 
-<p>For example, the following snippet from an HTML document specifies that the viewport width
-should exactly match the device screen width and that the ability to zoom should be disabled:</p>
+<p class="note"><strong>Note:</strong>
+When your page is rendered in a {@link android.webkit.WebView}, it does not use wide viewport mode
+(the page appears at full zoom) by default. You can enable wide viewport mode
+with {@link android.webkit.WebSettings#setUseWideViewPort setUseWideViewPort()}.</p>
+
+<p>You can define properties of the viewport for your web page, such as the width and initial zoom
+level, using the {@code &lt;meta name="viewport" ...>} tag in your document
+{@code &lt;head&gt;}.</p>
+
+<p>The following syntax shows all of the
+supported viewport properties and the types of values accepted by each one:</p>
+
+<pre>
+&lt;meta name="viewport"
+      content="
+          <b>height</b> = [<em>pixel_value</em> | "device-height"] ,
+          <b>width</b> = [<em>pixel_value</em> | "device-width"] ,
+          <b>initial-scale</b> = <em>float_value</em> ,
+          <b>minimum-scale</b> = <em>float_value</em> ,
+          <b>maximum-scale</b> = <em>float_value</em> ,
+          <b>user-scalable</b> = ["yes" | "no"]
+          " /&gt;
+</pre>
+
+<p>For example, the following {@code &lt;meta&gt;} tag specifies that the viewport width
+should exactly match the device screen's width and that the ability to zoom should be disabled:</p>
 
 <pre>
 &lt;head&gt;
@@ -104,235 +106,17 @@
 &lt;/head&gt;
 </pre>
 
-<p>That's an example of just two viewport properties. The following syntax shows all of the
-supported viewport properties and the general types of values accepted by each one:</p>
 
-<pre>
-&lt;meta name="viewport"
-      content="
-          <b>height</b> = [<em>pixel_value</em> | device-height] ,
-          <b>width</b> = [<em>pixel_value</em> | device-width ] ,
-          <b>initial-scale</b> = <em>float_value</em> ,
-          <b>minimum-scale</b> = <em>float_value</em> ,
-          <b>maximum-scale</b> = <em>float_value</em> ,
-          <b>user-scalable</b> = [yes | no] ,
-          <b>target-densitydpi</b> = [<em>dpi_value</em> | device-dpi |
-                               high-dpi | medium-dpi | low-dpi]
-          " /&gt;
-</pre>
+<p>When optimizing your site for mobile devices, you should usually set the width to
+{@code "device-width"} so the size fits exactly on all devices, then use CSS media queries to 
+flexibly adapt layouts to suit different screen sizes.
 
-<p>The following sections discuss how to use each of these viewport properties and exactly what the
-accepted values are.</p>
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-default.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 1.</strong> A web page with an image that's 320 pixels
-wide, in the Android Browser when there is no viewport metadata set (with "overview mode"
-enabled, the viewport is 800 pixels wide, by default).</p>
-</div>
-
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-width400.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 2.</strong> A web page with viewport {@code width=400} and
-"overview mode" enabled (the image in the web page is 320 pixels wide).</p>
-</div>
-
-
-<h3 id="ViewportSize">Defining the viewport size</h3>
-
-<p>Viewport's {@code height} and {@code width} properties allow you to specify the size of the
-viewport (the number of pixels available to the web page before it goes off screen).</p>
-
-<p>As mentioned in the introduction above, the Android Browser loads pages in "overview mode" by
-default (unless disable by the user), which sets the minimum viewport width to 800 pixels. So, if
-your web page specifies its size to be 320 pixels wide, then your page appears smaller than the
-visible screen (even if the physical screen is 320 pixels wide, because the viewport simulates a
-drawable area that's 800 pixels wide), as shown in figure 1. To avoid this effect, you should
-explicitly define the viewport {@code width} to match the width for which you have designed your web
-page.</p>
-
-<p>For example, if your web page is designed to be exactly 320 pixels wide, then you might
-want to specify that size for the viewport width:</p>
-
-<pre>
-&lt;meta name="viewport" content="width=320" /&gt;
-</pre>
-
-<p>In this case, your web page exactly fits the screen width, because the web page width and
-viewport width are the same.</p>
-
-<p class="note"><strong>Note:</strong> Width values that are greater than 10,000 are ignored and
-values less than (or equal to) 320 result in a value equal to the device-width (discussed below).
-Height values that are greater then 10,000 or less than 200 are also ignored.</p>
-
-<p>To demonstrate how this property affects the size of
-your web page, figure 2 shows a web page that contains an image that's 320 pixels
-wide, but with the viewport width set to 400.</p>
-
-
-<p class="note"><strong>Note:</strong> If you set the viewport width to match your web page width
-and the device's screen width does <em>not</em> match those dimensions, then the web page
-still fits the screen even if the device has a high or low-density screen, because the
-Android Browser and {@link android.webkit.WebView} scale web pages to match the perceived size on a
-medium-density screen, by default (as you can see in figure 2, when comparing the hdpi device to the
-mdpi device). Screen densities are discussed more in <a href="#ViewportDensity">Defining the
-viewport target density</a>.</p>
-
-
-<h4>Automatic sizing</h4>
-
-<p>As an alternative to specifying the viewport dimensions with exact pixels, you can set the
-viewport size to always match the dimensions of the device screen, by defining the
-viewport properties {@code height}
-and {@code width} with the values {@code device-height} and {@code device-width}, respectively. This
-is appropriate when you're developing a web application that has a fluid width (not fixed width),
-but you want it to appear as if it's fixed (to perfectly fit every screen as
-if the web page width is set to match each screen). For example:</p>
-
-<pre>
-&lt;meta name="viewport" content="width=device-width" /&gt;
-</pre>
-
-<p>This results in the viewport width matching whatever the current screen width is, as shown in
-figure 3. It's important to notice that, this results in images being scaled to fit the screen
-when the current device does not match the <a href="#ViewportDensity">target
-density</a>, which is medium-density if you don't specify otherwise. As a result, the image
-displayed on the high-density device in figure 3 is scaled up in order to match the width
-of a screen with a medium-density screen.</p>
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-initialscale.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 3.</strong> A web page with viewport {@code
-width=device-width} <em>or</em> {@code initial-scale=1.0}.</p>
-</div>
-
-<p class="note"><strong>Note:</strong> If you instead want {@code
-device-width} and {@code device-height} to match the physical screen pixels for every device,
-instead of scaling your web page to match the target density, then you must also include
-the {@code target-densitydpi} property with a value of {@code device-dpi}. This is discussed more in
-the section about <a href="#ViewportDensity">Defining the viewport density</a>. Otherwise, simply
-using {@code device-height} and {@code device-width} to define the viewport size makes your web page
-fit every device screen, but scaling occurs on your images in order to adjust for different screen
-densities.</p>
-
-
-
-<h3 id="ViewportScale">Defining the viewport scale</h3>
-
-<p>The scale of the viewport defines the level of zoom applied to the web page. Viewport
-properties allow you to specify the scale of your web page in the following ways:</p>
-<dl>
-  <dt>{@code initial-scale}</dt>
-  <dd>The initial scale of the page. The value is a float that indicates a multiplier for your web
-page size, relative to the screen size. For example, if you set the initial scale to "1.0" then the
-web page is displayed to match the resolution of the <a href="#ViewportDensity">target
-density</a> 1-to-1. If set to "2.0", then the page is enlarged (zoomed in) by a factor of 2.
-    <p>The default initial scale is calculated to fit the web page in the viewport size.
-Because the default viewport width is 800 pixels, if the device screen resolution is less than
-800 pixels wide, the initial scale is something less than 1.0, by default, in order to fit the
-800-pixel-wide page on the screen.</p></dd>
-
-  <dt>{@code minimum-scale}</dt>
-  <dd>The minimum scale to allow. The value is a float that indicates the minimum multiplier for
-your web page size, relative to the screen size. For example, if you set this to "1.0", then the
-page can't zoom out because the minimum size is 1-to-1 with the <a href="#ViewportDensity">target
-density</a>.</dd>
-
-  <dt>{@code maximum-scale}</dt>
-  <dd>The maximum scale to allow for the page. The value is a float that indicates the
-maximum multiplier for your web page size,
-relative to the screen size. For example, if you set this to "2.0", then the page can't
-zoom in more than 2 times the target size.</dd>
-
-  <dt>{@code user-scalable}</dt>
-  <dd>Whether the user can change the scale of the page at all (zoom in and out). Set to {@code yes}
-to allow scaling and {@code no} to disallow scaling. The default is {@code yes}. If you set
-this to {@code no}, then the {@code minimum-scale} and {@code maximum-scale} are ignored,
-because scaling is not possible.</dd>
-</dl>
-
-<p>All scale values must be within the range 0.01&ndash;10.</p>
-
-<p>For example:</p>
-
-<pre>
-&lt;meta name="viewport" content="initial-scale=1.0" /&gt;
-</pre>
-
-<p>This metadata sets the initial scale to be full sized, relative to the viewport's target
-density.</p>
+<p class="note"><strong>Note:</strong> You should disable user scaling only when you're certain
+that your web page layout is flexible and the content will fit the width of small screens.</p>
 
 
 
 
-<h3 id="ViewportDensity">Defining the viewport target density</h3>
-
-<p>The density of a device's screen is based on the screen resolution, as defined by the number of
-dots per inch (dpi). There are three screen
-density categories supported by Android: low (ldpi), medium (mdpi), and high (hdpi). A screen
-with low density has fewer available pixels per inch, whereas a screen with high density has more
-pixels per inch (compared to a medium density screen). The Android Browser and {@link
-android.webkit.WebView} target a medium density screen by default.</p>
-
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-initialscale-devicedpi.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 4.</strong> A web page with viewport {@code
-width=device-width} and {@code target-densitydpi=device-dpi}.</p>
-</div>
-
-
-<p>Because the default target density is medium, when users have a device with a low or high density
-screen, the Android Browser and {@link android.webkit.WebView} scale web pages (effectively zoom
-the pages) so they display at a
-size that matches the perceived appearance on a medium density screen. More specifically, the
-Android Browser and {@link android.webkit.WebView} apply approximately 1.5x scaling to web pages
-on a high density screen (because its screen pixels are smaller) and approximately 0.75x scaling to
-pages on a low density screen (because its screen pixels are bigger).</p>
-
-<p>Due to this default scaling, figures 1, 2, and 3 show the example web page at the same physical
-size on both the high and medium density device (the high-density device shows the
-web page with a default scale factor that is 1.5 times larger than the actual pixel resolution, to
-match the target density). This can introduce some undesirable artifacts in your images.
-For example, although an image appears the same size on a medium and high-density device, the image
-on the high-density device appears more blurry, because the image is designed to be 320 pixels
-wide, but is drawn with 480 pixels.</p>
-
-<p>You can change the target screen density for your web page using the {@code target-densitydpi}
-viewport property. It accepts the following values:</p>
-
-<ul>
-<li><code>device-dpi</code> - Use the device's native dpi as the target dpi. Default scaling never
-occurs.</li>
-<li><code>high-dpi</code> - Use hdpi as the target dpi. Medium and low density screens scale down
-as appropriate.</li>
-<li><code>medium-dpi</code> - Use mdpi as the target dpi. High density screens scale up and low
-density screens scale down. This is the default target density.</li>
-<li><code>low-dpi</code> - Use ldpi as the target dpi. Medium and high density screens scale up
-as appropriate.</li>
-<li><em><code>&lt;value&gt;</code></em> - Specify a dpi value to use as the target dpi. Values must
-be within the range 70&ndash;400.</li>
-</ul></p>
-
-<p>For example, to prevent the Android Browser and {@link android.webkit.WebView} from scaling
-your web page for different screen densities, set
-the {@code target-densitydpi} viewport property to {@code device-dpi}. When you do, the page is
-not scaled. Instead, the page is displayed at a size that matches the current screen's
-density. In this case, you should also define the viewport width to match the device width, so your
-web page naturally fits the screen size. For example:</p>
-
-<pre>
-&lt;meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" /&gt;
-</pre>
-
-<p>Figure 4 shows a web page using these viewport settings&mdash;the high-density device
-now displays the page smaller because its physical pixels are smaller than those on the
-medium-density device, so no scaling occurs and the 320-pixel-wide image is drawn using exactly 320
-pixels on both screens. (This is how you should define your viewport if
-you want to customize your web page based on screen density and provide different image assets for
-different densities, <a href="#DensityCSS">with CSS</a> or
-<a href="#DensityJS">with JavaScript</a>.)</p>
 
 
 <h2 id="DensityCSS">Targeting Device Density with CSS</h2>
@@ -349,17 +133,9 @@
 <pre>
 &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.5)" href="hdpi.css" /&gt;
 &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.0)" href="mdpi.css" /&gt;
-&lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 0.75)" href="ldpi.css" /&gt;
 </pre>
 
 
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-width-devicedpi-css.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 5.</strong> A web page with CSS that's targetted to
-specific screen densities using the {@code -webkit-device-pixel-ratio} media feature. Notice
-that the hdpi device shows a different image that's applied in CSS.</p>
-</div>
-
 <p>Or, specify the different styles in one stylesheet:</p>
 
 <pre class="no-pretty-print">
@@ -382,27 +158,10 @@
 }
 </pre>
 
-<p class="note"><strong>Note:</strong> The default style for {@code #header} applies the image
-designed for medium-density devices in order to support devices running a version of Android less
-than 2.0, which do not support the {@code -webkit-device-pixel-ratio} media feature.</p>
 
-<p>The types of styles you might want to adjust based on the screen density depend on how you've
-defined your viewport properties. To provide fully-customized styles that tailor your web page for
-each of the supported densities, you should set your viewport properties so the viewport width and
-density match the device. That is:</p>
-
-<pre>
-&lt;meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" /&gt;
-</pre>
-
-<p>This way, the Android Browser and {@link android.webkit.WebView} do not perform scaling on your
-web page and the viewport width
-matches the screen width exactly. On their own, these viewport properties create results shown in
-figure 4. However, by adding some custom CSS using the {@code -webkit-device-pixel-ratio} media
-feature, you can apply different styles. For example, figure 5 shows a web page with these viewport
-properties and also some CSS added that applies a high-resolution image for high-density
-screens.</p>
-
+<p>For more information about handling different screen densities, especially images, see
+<a href="http://www.html5rocks.com/en/mobile/high-dpi/" class="external-link">High
+  DPI Images for Variable Pixel Densities</a>.</li>
 
 
 <h2 id="DensityJS">Targeting Device Density with JavaScript</h2>
@@ -432,8 +191,3 @@
 </pre>
 
 
-
-
-
-
-
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index c87be06..9b46b5b 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -136,7 +136,6 @@
 setUserAgentString()}, then query the custom user agent in your web page to verify that the
 client requesting your web page is actually your Android application.</p>
 
-from your Android SDK {@code tools/} directory
 <h3 id="BindingJavaScript">Binding JavaScript code to Android code</h3>
 
 <p>When developing a web application that's designed specifically for the {@link
diff --git a/docs/html/images/distribute/hichat-n5-port.jpg b/docs/html/images/distribute/hichat-n5-port.jpg
new file mode 100644
index 0000000..b93e983
--- /dev/null
+++ b/docs/html/images/distribute/hichat-n5-port.jpg
Binary files differ
diff --git a/docs/html/images/distribute/indian-rummy-n4-land.jpg b/docs/html/images/distribute/indian-rummy-n4-land.jpg
new file mode 100644
index 0000000..61943fc
--- /dev/null
+++ b/docs/html/images/distribute/indian-rummy-n4-land.jpg
Binary files differ
diff --git a/docs/html/images/distribute/zombie-ragdoll-n5-land.jpg b/docs/html/images/distribute/zombie-ragdoll-n5-land.jpg
new file mode 100644
index 0000000..e2bf6b5
--- /dev/null
+++ b/docs/html/images/distribute/zombie-ragdoll-n5-land.jpg
Binary files differ
diff --git a/docs/html/images/gcm/CCS-ack.png b/docs/html/images/gcm/CCS-ack.png
new file mode 100644
index 0000000..bce2ab2
--- /dev/null
+++ b/docs/html/images/gcm/CCS-ack.png
Binary files differ
diff --git a/docs/html/images/gcm/GCM-arch.png b/docs/html/images/gcm/GCM-arch.png
new file mode 100644
index 0000000..e8ffb15
--- /dev/null
+++ b/docs/html/images/gcm/GCM-arch.png
Binary files differ
diff --git a/docs/html/images/gp-edu-ads-iab.png b/docs/html/images/gp-edu-ads-iab.png
new file mode 100644
index 0000000..07ccaee
--- /dev/null
+++ b/docs/html/images/gp-edu-ads-iab.png
Binary files differ
diff --git a/docs/html/images/gp-edu-apps-n7.jpg b/docs/html/images/gp-edu-apps-n7.jpg
new file mode 100644
index 0000000..c2e3e21
--- /dev/null
+++ b/docs/html/images/gp-edu-apps-n7.jpg
Binary files differ
diff --git a/docs/html/images/gp-edu-hero14.jpg b/docs/html/images/gp-edu-hero14.jpg
new file mode 100644
index 0000000..69b02e2
--- /dev/null
+++ b/docs/html/images/gp-edu-hero14.jpg
Binary files differ
diff --git a/docs/html/images/gp-edu-hero7.png b/docs/html/images/gp-edu-hero7.png
deleted file mode 100644
index 84abdef..0000000
--- a/docs/html/images/gp-edu-hero7.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-edu-knum-landscape.png b/docs/html/images/gp-edu-knum-landscape.png
deleted file mode 100644
index aaec6dc..0000000
--- a/docs/html/images/gp-edu-knum-landscape.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/kk-saf2-n5.jpg b/docs/html/images/kk-saf2-n5.jpg
index c96d5d4..1c54a95 100644
--- a/docs/html/images/kk-saf2-n5.jpg
+++ b/docs/html/images/kk-saf2-n5.jpg
Binary files differ
diff --git a/docs/html/images/nfc/dual-mode.png b/docs/html/images/nfc/dual-mode.png
index 8e484a8..ea32551 100644
--- a/docs/html/images/nfc/dual-mode.png
+++ b/docs/html/images/nfc/dual-mode.png
Binary files differ
diff --git a/docs/html/images/nfc/dual-mode@2x.png b/docs/html/images/nfc/dual-mode@2x.png
new file mode 100644
index 0000000..47184f8
--- /dev/null
+++ b/docs/html/images/nfc/dual-mode@2x.png
Binary files differ
diff --git a/docs/html/images/nfc/host-based-card.png b/docs/html/images/nfc/host-based-card.png
index 0431b27..9d5d190 100644
--- a/docs/html/images/nfc/host-based-card.png
+++ b/docs/html/images/nfc/host-based-card.png
Binary files differ
diff --git a/docs/html/images/nfc/host-based-card@2x.png b/docs/html/images/nfc/host-based-card@2x.png
new file mode 100644
index 0000000..9606f64
--- /dev/null
+++ b/docs/html/images/nfc/host-based-card@2x.png
Binary files differ
diff --git a/docs/html/images/nfc/protocol-stack.png b/docs/html/images/nfc/protocol-stack.png
index 71bdfe9..e4d118d 100644
--- a/docs/html/images/nfc/protocol-stack.png
+++ b/docs/html/images/nfc/protocol-stack.png
Binary files differ
diff --git a/docs/html/images/nfc/protocol-stack@2x.png b/docs/html/images/nfc/protocol-stack@2x.png
new file mode 100644
index 0000000..d7856e8
--- /dev/null
+++ b/docs/html/images/nfc/protocol-stack@2x.png
Binary files differ
diff --git a/docs/html/images/nfc/secure-element.png b/docs/html/images/nfc/secure-element.png
index c8133de..9ade250 100644
--- a/docs/html/images/nfc/secure-element.png
+++ b/docs/html/images/nfc/secure-element.png
Binary files differ
diff --git a/docs/html/images/nfc/secure-element@2x.png b/docs/html/images/nfc/secure-element@2x.png
new file mode 100644
index 0000000..bb4dadc
--- /dev/null
+++ b/docs/html/images/nfc/secure-element@2x.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle-projected.png b/docs/html/images/opengl/ogl-triangle-projected.png
index d10bbdc..4b18b98 100644
--- a/docs/html/images/opengl/ogl-triangle-projected.png
+++ b/docs/html/images/opengl/ogl-triangle-projected.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle-touch.png b/docs/html/images/opengl/ogl-triangle-touch.png
index 35177a4..8323dd9 100644
--- a/docs/html/images/opengl/ogl-triangle-touch.png
+++ b/docs/html/images/opengl/ogl-triangle-touch.png
Binary files differ
diff --git a/docs/html/images/opengl/ogl-triangle.png b/docs/html/images/opengl/ogl-triangle.png
index 3d4a385..66047ab 100644
--- a/docs/html/images/opengl/ogl-triangle.png
+++ b/docs/html/images/opengl/ogl-triangle.png
Binary files differ
diff --git a/docs/html/images/tools/sync-project.png b/docs/html/images/tools/sync-project.png
new file mode 100644
index 0000000..09e1835
--- /dev/null
+++ b/docs/html/images/tools/sync-project.png
Binary files differ
diff --git a/docs/html/images/training/imm-states.png b/docs/html/images/training/imm-states.png
new file mode 100644
index 0000000..59c4092
--- /dev/null
+++ b/docs/html/images/training/imm-states.png
Binary files differ
diff --git a/docs/html/images/training/imm-sticky.png b/docs/html/images/training/imm-sticky.png
new file mode 100644
index 0000000..31b118a
--- /dev/null
+++ b/docs/html/images/training/imm-sticky.png
Binary files differ
diff --git a/docs/html/images/training/system-ui.png b/docs/html/images/training/system-ui.png
index a3aea65..2c13c75 100644
--- a/docs/html/images/training/system-ui.png
+++ b/docs/html/images/training/system-ui.png
Binary files differ
diff --git a/docs/html/images/webapps/web-viewport-320@2x.png b/docs/html/images/webapps/web-viewport-320@2x.png
new file mode 100644
index 0000000..f6b2bac
--- /dev/null
+++ b/docs/html/images/webapps/web-viewport-320@2x.png
Binary files differ
diff --git a/docs/html/images/webapps/web-viewport-default@2x.png b/docs/html/images/webapps/web-viewport-default@2x.png
new file mode 100644
index 0000000..a3f8d53
--- /dev/null
+++ b/docs/html/images/webapps/web-viewport-default@2x.png
Binary files differ
diff --git a/docs/html/images/webapps/web-viewport-devicewidth@2x.png b/docs/html/images/webapps/web-viewport-devicewidth@2x.png
new file mode 100644
index 0000000..3832f4c
--- /dev/null
+++ b/docs/html/images/webapps/web-viewport-devicewidth@2x.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 5c805f8..3e59068 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -14,78 +14,62 @@
         <a href="" class="slideshow-next">Next</a>
         <div class="frame">
             <ul>
+                <!-- set explicit widths as needed to prevent overflow issues -->
 
                 <li class="item carousel-home">
-                    <div class="content-left col-7">
-                        <a href="/about/versions/kitkat.html"><img src="/images/home/kk-hero.jpg" style="width:242px;padding-top:72px;"></a>
-                    </div>
-                    <div class="content-right col-6">
+                  <div class="content-left col-7" style="width:400px;">
+                    <a href="{@docRoot}about/versions/kitkat.html">
+                      <img src="{@docRoot}images/home/kk-hero.jpg" width="242" style="padding-top:72px;">
+                    </a>
+                  </div>
+                  <div class="content-right col-4" style="width:340px;">
                     <h1>Android 4.4 KitKat!</h1>
                     <p>A new version of Android is here, with great new features, APIs, and tools for developers.</p>
                     <p>Android 4.4 is built to run on more devices than ever before, and gives you more ways to showcase your content and create beautiful, useful, and innovative apps.</p>
                     <p>Learn about what's new in the Platform Highlights and see the API Overview for details.</p>
-                    <p><a href="/about/versions/kitkat.html" class="button">Check out the highlights</a></p>
-                    </div>
+                    <p><a href="{@docRoot}about/versions/kitkat.html" class="button">Check out the highlights</a></p>
+                  </div>
                 </li>
 
                 <li class="item carousel-home">
-                    <div class="content-left col-11" style="padding-top:65px;">
-                      <a href="https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1">
-                                          <img src="/images/title-devbytes-kk.jpg" style="margin-top:22px;width:600px;">
-                        </a>
-                      </div>
-
-                    <div class="content-right col-4">
+                  <div class="content-left col-11" style="padding-top:65px;">
+                    <a href="https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1">
+                      <img src="{@docRoot}images/title-devbytes-kk.jpg" style="margin-top:0px;width:600px;">
+                    </a>
+                  </div>
+                  <div class="content-right col-4">
                     <h1 style="white-space:nowrap;line-height:1.2em;">DevBytes: <br />Android 4.4</h1>
                     <p>Join the DevBytes team for a look at what's new in Android 4.4 KitKat&nbsp;&mdash; new ways to make your apps beautiful, printing, storage access framework, and more.</p>
                     <p><a href="https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1" class="button">Watch the video </a></p>
-                    </div>
+                  </div>
                 </li>
 
-
                 <li class="item carousel-home">
-                    <div class="content-left col-10"><a href="/design/patterns/new.html">
-                        <img src="/design/media/design_elements_landing.png" style="margin-top:30px">
-                        </a>
-                    </div>
-                    <div class="content-right col-5">
+                  <div class="content-left col-19" style="width:580px;">
+                    <a href="{@docRoot}design/patterns/new.html">
+                      <img src="{@docRoot}design/media/design_elements_landing.png" style="margin-top:30px">
+                    </a>
+                  </div>
+                  <div class="content-right col-4" style="width:280px;">
                     <h1>Design for Android KitKat</h1>
                     <p>Android KitKat brings a refreshed UI with updated styles, patterns, and gestures to use in your apps. </p>
                     <p>We've updated the Android Design guidelines and added new pages on branding, fullscreen, and more. </p>
-                    <p><a href="/design/patterns/new.html" class="button">See what's new</a></p>
-                    </div>
+                    <p><a href="{@docRoot}design/patterns/new.html" class="button">See what's new</a></p>
+                  </div>
                 </li>
 
-                <!--<li class="item carousel-home">
-                    <div class="content-left col-11" style="padding-top:65px;">
-                      <a href="http://www.youtube.com/watch?v=6QHkv-bSlds&list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF&index=1">
-                                          <img src="/images/title-adia-kk.png" style="margin-top:22px;width:600px;">
-                        </a>
-                      </div>
-
-                    <div class="content-right col-4">
+                <li class="item carousel-home">
+                  <div class="content-left col-11" style="padding-top:65px;">
+                    <a href="http://www.youtube.com/watch?v=6QHkv-bSlds&list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF&index=1">
+                      <img src="{@docRoot}images/title-adia-kk.png" style="margin-top:0px;width:600px;">
+                    </a>
+                  </div>
+                  <div class="content-right col-4">
                     <h1 style="white-space:nowrap;line-height:1.2em;">ADIA: <br />Android 4.4</h1>
                     </p>Join the Android Design in Action team for a walkthrough of new developer features, UX changes, and updates to design guidelines in Android 4.4.</p>
                     <p><a href="http://www.youtube.com/watch?v=6QHkv-bSlds&list=PLWz5rJ2EKKc8j2B95zGMb8muZvrIy-wcF&index=1" class="button">Watch the video </a></p>
-                    </div>
-                </li> -->
-               <!-- <li class="item carousel-home">
-                    <div class="content-left col-11" style="padding-top:10px;">
-                        <a href="/channels/io2013.html">
-                          <img src="/images/home/io-videos-2013.png" style="margin:60px 0 0;
-                          box-shadow: 3px 10px 18px 1px #999;">
-                        </a>
-                    </div>
-                    <div class="content-right col-4">
-                    <h1>Hands-on with New KitKat Features</h1>
-                    <p>If you weren't able to attend Google I/O in person or couldn't make it
-                    to all the talks, you can catch up on the action
-                    with all the recordings, brought to you by
-                    <a href="http://developers.google.com/live">Google Developers Live</a>.</p>
-                    <p><a href="/channels/io2013.html" class="button"
-                    >See the Android talks</a></p>
-                    </div>
-                </li> -->
+                  </div>
+                </li>
            </ul>
         </div>
     </div>
diff --git a/docs/html/samples/index.jd b/docs/html/samples/index.jd
index c1213b6..ab15e32 100644
--- a/docs/html/samples/index.jd
+++ b/docs/html/samples/index.jd
@@ -1,5 +1,5 @@
 page.title=Samples
-page.tags="samples","examples","code"
+page.tags=samples,examples,code
 
 @jd:body
 
diff --git a/docs/html/samples/samples_toc.cs b/docs/html/samples/samples_toc.cs
index 3de31b9..18f7034 100644
--- a/docs/html/samples/samples_toc.cs
+++ b/docs/html/samples/samples_toc.cs
@@ -13,4 +13,6 @@
     </div>
   </li>
 
-  <li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Background" title="Background">Background</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/repeatingAlarm/index.html" title="repeatingAlarm">repeatingAlarm</a></div><ul><li><a href="/samples/repeatingAlarm/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/repeatingAlarm/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/repeatingAlarm/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.repeatingalarm">com.example.android.repeatingalarm/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.html" title="RepeatingAlarmFragment.java">RepeatingAlarmFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Connectivity" title="Connectivity">Connectivity</a></div><ul style="display: none;"><li class="nav-section"><div class="nav-section-header"><a href="/samples/BluetoothLeGatt/index.html" title="BluetoothLeGatt">BluetoothLeGatt</a></div><ul style="display: none;"><li><a href="/samples/BluetoothLeGatt/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/gatt_services_characteristics.html" title="gatt_services_characteristics.xml">gatt_services_characteristics.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/listitem_device.html" title="listitem_device.xml">listitem_device.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/menu/gatt_services.html" title="gatt_services.xml">gatt_services.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul style="display: none;"><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.bluetoothlegatt">com.example.android.bluetoothlegatt/</a></div><ul style="display: none;"><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.html" title="BluetoothLeService.java">BluetoothLeService.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.html" title="DeviceControlActivity.java">DeviceControlActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html" title="DeviceScanActivity.java">DeviceScanActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/SampleGattAttributes.html" title="SampleGattAttributes.java">SampleGattAttributes.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/NetworkConnect/index.html" title="NetworkConnect">NetworkConnect</a></div><ul><li><a href="/samples/NetworkConnect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/NetworkConnect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/NetworkConnect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/NetworkConnect/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/NetworkConnect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/NetworkConnect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/NetworkConnect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.networkconnect">com.example.android.networkconnect/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNetworking/index.html" title="BasicNetworking">BasicNetworking</a></div><ul><li><a href="/samples/BasicNetworking/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNetworking/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNetworking/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNetworking/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicNetworking/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNetworking/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNetworking/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnetworking">com.example.android.basicnetworking/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicSyncAdapter/index.html" title="BasicSyncAdapter">BasicSyncAdapter</a></div><ul><li><a href="/samples/BasicSyncAdapter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_entry_list.html" title="activity_entry_list.xml">activity_entry_list.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values/attrs.html" title="attrs.xml">attrs.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimen.html" title="dimen.xml">dimen.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/xml/authenticator.html" title="authenticator.xml">authenticator.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/xml/syncadapter.html" title="syncadapter.xml">syncadapter.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicsyncadapter">com.example.android.basicsyncadapter/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListActivity.html" title="EntryListActivity.java">EntryListActivity.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListFragment.html" title="EntryListFragment.java">EntryListFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncAdapter.html" title="SyncAdapter.java">SyncAdapter.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncService.html" title="SyncService.java">SyncService.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.html" title="SyncUtils.java">SyncUtils.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="net">net/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.html" title="FeedParser.java">FeedParser.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="provider">provider/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.html" title="FeedContract.java">FeedContract.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.html" title="FeedProvider.java">FeedProvider.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="accounts">accounts/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.html" title="GenericAccountService.java">GenericAccountService.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="db">db/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.html" title="SelectionBuilder.java">SelectionBuilder.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Content" title="Content">Content</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicContactables/index.html" title="BasicContactables">BasicContactables</a></div><ul><li><a href="/samples/BasicContactables/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicContactables/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicContactables/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicContactables/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicContactables/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicContactables/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicContactables/res/xml/searchable.html" title="searchable.xml">searchable.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basiccontactables">com.example.android.basiccontactables/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/ContactablesLoaderCallbacks.html" title="ContactablesLoaderCallbacks.java">ContactablesLoaderCallbacks.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AppRestrictions/index.html" title="AppRestrictions">AppRestrictions</a></div><ul><li><a href="/samples/AppRestrictions/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AppRestrictions/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AppRestrictions/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/AppRestrictions/res/layout/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AppRestrictions/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AppRestrictions/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/AppRestrictions/res/xml/custom_prefs.html" title="custom_prefs.xml">custom_prefs.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.apprestrictions">com.example.android.apprestrictions/</a></div><ul><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsActivity.html" title="CustomRestrictionsActivity.java">CustomRestrictionsActivity.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.html" title="CustomRestrictionsFragment.java">CustomRestrictionsFragment.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.html" title="GetRestrictionsReceiver.java">GetRestrictionsReceiver.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/StorageClient/index.html" title="StorageClient">StorageClient</a></div><ul><li><a href="/samples/StorageClient/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/StorageClient/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/StorageClient/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/StorageClient/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/StorageClient/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/StorageClient/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/StorageClient/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/StorageClient/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.storageclient">com.example.android.storageclient/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.storageclient/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.storageclient/StorageClientFragment.html" title="StorageClientFragment.java">StorageClientFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Input" title="Input">Input</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMultitouch/index.html" title="BasicMultitouch">BasicMultitouch</a></div><ul><li><a href="/samples/BasicMultitouch/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMultitouch/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMultitouch/res/layout/layout_mainactivity.html" title="layout_mainactivity.xml">layout_mainactivity.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmultitouch">com.example.android.basicmultitouch/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.html" title="Pools.java">Pools.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/TouchDisplayView.html" title="TouchDisplayView.java">TouchDisplayView.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicGestureDetect/index.html" title="BasicGestureDetect">BasicGestureDetect</a></div><ul><li><a href="/samples/BasicGestureDetect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicgesturedetect">com.example.android.basicgesturedetect/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/BasicGestureDetectFragment.html" title="BasicGestureDetectFragment.java">BasicGestureDetectFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.html" title="GestureListener.java">GestureListener.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Media" title="Media">Media</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaRouter/index.html" title="BasicMediaRouter">BasicMediaRouter</a></div><ul><li><a href="/samples/BasicMediaRouter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/display.html" title="display.xml">display.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediarouter">com.example.android.basicmediarouter/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.html" title="SamplePresentation.java">SamplePresentation.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaDecoder/index.html" title="BasicMediaDecoder">BasicMediaDecoder</a></div><ul><li><a href="/samples/BasicMediaDecoder/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable/selector_play.html" title="selector_play.xml">selector_play.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/menu/action_menu.html" title="action_menu.xml">action_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="raw">raw/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/raw/vid_bigbuckbunny.html" title="vid_bigbuckbunny.mp4">vid_bigbuckbunny.mp4</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediadecoder">com.example.android.basicmediadecoder/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.basicmediadecoder/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.media">com.example.android.common.media/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/CameraHelper.html" title="CameraHelper.java">CameraHelper.java</a></li><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.html" title="MediaCodecWrapper.java">MediaCodecWrapper.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Security" title="Security">Security</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAndroidKeyStore/index.html" title="BasicAndroidKeyStore">BasicAndroidKeyStore</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicandroidkeystore">com.example.android.basicandroidkeystore/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.html" title="BasicAndroidKeyStoreFragment.java">BasicAndroidKeyStoreFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/SecurityConstants.html" title="SecurityConstants.java">SecurityConstants.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Testing" title="Testing">Testing</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/ActivityInstrumentation/index.html" title="ActivityInstrumentation">ActivityInstrumentation</a></div><ul><li><a href="/samples/ActivityInstrumentation/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.activityinstrumentation">com.example.android.activityinstrumentation/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.activityinstrumentation/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=UI" title="UI">UI</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAccessibility/index.html" title="BasicAccessibility">BasicAccessibility</a></div><ul><li><a href="/samples/BasicAccessibility/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/partly_cloudy.html" title="partly_cloudy.png">partly_cloudy.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAccessibility/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicAccessibility/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicaccessibility">com.example.android.basicaccessibility/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/DialView.html" title="DialView.java">DialView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/HorizontalPaging/index.html" title="HorizontalPaging">HorizontalPaging</a></div><ul><li><a href="/samples/HorizontalPaging/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/HorizontalPaging/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/fragment_main_dummy.html" title="fragment_main_dummy.xml">fragment_main_dummy.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/styles.html" title="styles.xml">styles.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.horizontalpaging">com.example.android.horizontalpaging/</a></div><ul><li><a href="/samples/HorizontalPaging/src/com.example.android.horizontalpaging/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ShareActionProvider/index.html" title="ShareActionProvider">ShareActionProvider</a></div><ul><li><a href="/samples/ShareActionProvider/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ShareActionProvider/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_image.html" title="item_image.xml">item_image.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_text.html" title="item_text.xml">item_text.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ShareActionProvider/res/menu/main_menu.html" title="main_menu.xml">main_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.shareactionprovider">com.example.android.actionbarcompat.shareactionprovider/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="content">content/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.html" title="AssetProvider.java">AssetProvider.java</a></li><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.html" title="ContentItem.java">ContentItem.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Styled/index.html" title="Styled">Styled</a></div><ul><li><a href="/samples/Styled/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/Styled/res/drawable/pressed_background.html" title="pressed_background.xml">pressed_background.xml</a></li><li><a href="/samples/Styled/res/drawable/progress_horizontal.html" title="progress_horizontal.xml">progress_horizontal.xml</a></li><li><a href="/samples/Styled/res/drawable/selectable_background.html" title="selectable_background.xml">selectable_background.xml</a></li><li><a href="/samples/Styled/res/drawable/spinner_background_ab.html" title="spinner_background_ab.xml">spinner_background_ab.xml</a></li><li><a href="/samples/Styled/res/drawable/tab_indicator_ab.html" title="tab_indicator_ab.xml">tab_indicator_ab.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Styled/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Styled/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Styled/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Styled/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Styled/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/Styled/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Styled/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Styled/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/Styled/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.styled">com.example.android.actionbarcompat.styled/</a></div><ul><li><a href="/samples/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Basic/index.html" title="Basic">Basic</a></div><ul><li><a href="/samples/Basic/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Basic/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Basic/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Basic/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Basic/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Basic/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values/ids.html" title="ids.xml">ids.xml</a></li><li><a href="/samples/Basic/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Basic/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Basic/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.basic">com.example.android.actionbarcompat.basic/</a></div><ul><li><a href="/samples/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ImmersiveMode/index.html" title="ImmersiveMode">ImmersiveMode</a></div><ul><li><a href="/samples/ImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.immersivemode">com.example.android.immersivemode/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/ImmersiveModeFragment.html" title="ImmersiveModeFragment.java">ImmersiveModeFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextSwitcher/index.html" title="TextSwitcher">TextSwitcher</a></div><ul><li><a href="/samples/TextSwitcher/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextSwitcher/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextSwitcher/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextSwitcher/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextSwitcher/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textswitcher">com.example.android.textswitcher/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.textswitcher/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BorderlessButtons/index.html" title="BorderlessButtons">BorderlessButtons</a></div><ul><li><a href="/samples/BorderlessButtons/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BorderlessButtons/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BorderlessButtons/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.borderlessbuttons">com.example.android.borderlessbuttons/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.borderlessbuttons/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNotifications/index.html" title="BasicNotifications">BasicNotifications</a></div><ul><li><a href="/samples/BasicNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNotifications/res/layout/sample_layout.html" title="sample_layout.xml">sample_layout.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnotifications">com.example.android.basicnotifications/</a></div><ul><li><a href="/samples/BasicNotifications/src/com.example.android.basicnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AdvancedImmersiveMode/index.html" title="AdvancedImmersiveMode">AdvancedImmersiveMode</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.advancedimmersivemode">com.example.android.advancedimmersivemode/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.html" title="AdvancedImmersiveModeFragment.java">AdvancedImmersiveModeFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicImmersiveMode/index.html" title="BasicImmersiveMode">BasicImmersiveMode</a></div><ul><li><a href="/samples/BasicImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicimmersivemode">com.example.android.basicimmersivemode/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/BasicImmersiveModeFragment.html" title="BasicImmersiveModeFragment.java">BasicImmersiveModeFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomChoiceList/index.html" title="CustomChoiceList">CustomChoiceList</a></div><ul><li><a href="/samples/CustomChoiceList/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="color">color/</a></div><ul><li><a href="/samples/CustomChoiceList/res/color/hideable_text_color.html" title="hideable_text_color.xml">hideable_text_color.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable/ic_hideable_item.html" title="ic_hideable_item.xml">ic_hideable_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_checked.html" title="ic_hideable_item_checked.png">ic_hideable_item_checked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_unchecked.html" title="ic_hideable_item_unchecked.png">ic_hideable_item_unchecked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomChoiceList/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customchoicelist">com.example.android.customchoicelist/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/CheckableLinearLayout.html" title="CheckableLinearLayout.java">CheckableLinearLayout.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/DoneBar/index.html" title="DoneBar">DoneBar</a></div><ul><li><a href="/samples/DoneBar/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/sample_dashboard_item_background.9.html" title="sample_dashboard_item_background.9.png">sample_dashboard_item_background.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done.html" title="actionbar_custom_view_done.xml">actionbar_custom_view_done.xml</a></li><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done_cancel.html" title="actionbar_custom_view_done_cancel.xml">actionbar_custom_view_done_cancel.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_bar.html" title="activity_done_bar.xml">activity_done_bar.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_button.html" title="activity_done_button.xml">activity_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_sample_dashboard.html" title="activity_sample_dashboard.xml">activity_sample_dashboard.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_cancel_button.html" title="include_cancel_button.xml">include_cancel_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_done_button.html" title="include_done_button.xml">include_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/sample_dashboard_item.html" title="sample_dashboard_item.xml">sample_dashboard_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/DoneBar/res/menu/cancel.html" title="cancel.xml">cancel.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/DoneBar/res/values/activitycards-strings.html" title="activitycards-strings.xml">activitycards-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/DoneBar/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/DoneBar/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.donebar">com.example.android.donebar/</a></div><ul><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneBarActivity.html" title="DoneBarActivity.java">DoneBarActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneButtonActivity.html" title="DoneButtonActivity.java">DoneButtonActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ListPopupMenu/index.html" title="ListPopupMenu">ListPopupMenu</a></div><ul><li><a href="/samples/ListPopupMenu/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ListPopupMenu/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ListPopupMenu/res/menu/popup.html" title="popup.xml">popup.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.listpopupmenu">com.example.android.actionbarcompat.listpopupmenu/</a></div><ul><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.html" title="PopupListFragment.java">PopupListFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomNotifications/index.html" title="CustomNotifications">CustomNotifications</a></div><ul><li><a href="/samples/CustomNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot.html" title="robot.png">robot.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot_expanded.html" title="robot_expanded.png">robot_expanded.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification.html" title="notification.xml">notification.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification_expanded.html" title="notification_expanded.xml">notification_expanded.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v9">values-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-v9/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customnotifications">com.example.android.customnotifications/</a></div><ul><li><a href="/samples/CustomNotifications/src/com.example.android.customnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/topic.html#t=Views" title="Views">Views</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextLinkify/index.html" title="TextLinkify">TextLinkify</a></div><ul><li><a href="/samples/TextLinkify/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextLinkify/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextLinkify/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextLinkify/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextLinkify/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textlinkify">com.example.android.textlinkify/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.textlinkify/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li></ul>
+
+  <li class="nav-section"><div class="nav-section-header"><a href="/samples/background.html" title="Background">Background</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/repeatingAlarm/index.html" title="repeatingAlarm">repeatingAlarm</a></div><ul><li><a href="/samples/repeatingAlarm/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/repeatingAlarm/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/repeatingAlarm/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.repeatingalarm">com.example.android.repeatingalarm/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.html" title="RepeatingAlarmFragment.java">RepeatingAlarmFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/connectivity.html" title="Connectivity">Connectivity</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BluetoothLeGatt/index.html" title="BluetoothLeGatt">BluetoothLeGatt</a></div><ul><li><a href="/samples/BluetoothLeGatt/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/gatt_services_characteristics.html" title="gatt_services_characteristics.xml">gatt_services_characteristics.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/listitem_device.html" title="listitem_device.xml">listitem_device.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/menu/gatt_services.html" title="gatt_services.xml">gatt_services.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.bluetoothlegatt">com.example.android.bluetoothlegatt/</a></div><ul><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.html" title="BluetoothLeService.java">BluetoothLeService.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.html" title="DeviceControlActivity.java">DeviceControlActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html" title="DeviceScanActivity.java">DeviceScanActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/SampleGattAttributes.html" title="SampleGattAttributes.java">SampleGattAttributes.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/NetworkConnect/index.html" title="NetworkConnect">NetworkConnect</a></div><ul><li><a href="/samples/NetworkConnect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/NetworkConnect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/NetworkConnect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/NetworkConnect/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/NetworkConnect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/NetworkConnect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/NetworkConnect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.networkconnect">com.example.android.networkconnect/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNetworking/index.html" title="BasicNetworking">BasicNetworking</a></div><ul><li><a href="/samples/BasicNetworking/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNetworking/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNetworking/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNetworking/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicNetworking/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNetworking/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNetworking/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnetworking">com.example.android.basicnetworking/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicSyncAdapter/index.html" title="BasicSyncAdapter">BasicSyncAdapter</a></div><ul><li><a href="/samples/BasicSyncAdapter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_entry_list.html" title="activity_entry_list.xml">activity_entry_list.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values/attrs.html" title="attrs.xml">attrs.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimen.html" title="dimen.xml">dimen.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/xml/authenticator.html" title="authenticator.xml">authenticator.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/xml/syncadapter.html" title="syncadapter.xml">syncadapter.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicsyncadapter">com.example.android.basicsyncadapter/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListActivity.html" title="EntryListActivity.java">EntryListActivity.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListFragment.html" title="EntryListFragment.java">EntryListFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncAdapter.html" title="SyncAdapter.java">SyncAdapter.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncService.html" title="SyncService.java">SyncService.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.html" title="SyncUtils.java">SyncUtils.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="net">net/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.html" title="FeedParser.java">FeedParser.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="provider">provider/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.html" title="FeedContract.java">FeedContract.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.html" title="FeedProvider.java">FeedProvider.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="accounts">accounts/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.html" title="GenericAccountService.java">GenericAccountService.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="db">db/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.html" title="SelectionBuilder.java">SelectionBuilder.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/content.html" title="Content">Content</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicContactables/index.html" title="BasicContactables">BasicContactables</a></div><ul><li><a href="/samples/BasicContactables/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicContactables/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicContactables/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicContactables/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicContactables/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicContactables/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicContactables/res/xml/searchable.html" title="searchable.xml">searchable.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basiccontactables">com.example.android.basiccontactables/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/ContactablesLoaderCallbacks.html" title="ContactablesLoaderCallbacks.java">ContactablesLoaderCallbacks.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AppRestrictions/index.html" title="AppRestrictions">AppRestrictions</a></div><ul><li><a href="/samples/AppRestrictions/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AppRestrictions/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AppRestrictions/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/AppRestrictions/res/layout/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AppRestrictions/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AppRestrictions/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/AppRestrictions/res/xml/custom_prefs.html" title="custom_prefs.xml">custom_prefs.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.apprestrictions">com.example.android.apprestrictions/</a></div><ul><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsActivity.html" title="CustomRestrictionsActivity.java">CustomRestrictionsActivity.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.html" title="CustomRestrictionsFragment.java">CustomRestrictionsFragment.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.html" title="GetRestrictionsReceiver.java">GetRestrictionsReceiver.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/StorageClient/index.html" title="StorageClient">StorageClient</a></div><ul><li><a href="/samples/StorageClient/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/StorageClient/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/StorageClient/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/StorageClient/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/StorageClient/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/StorageClient/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/StorageClient/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/StorageClient/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.storageclient">com.example.android.storageclient/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.storageclient/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.storageclient/StorageClientFragment.html" title="StorageClientFragment.java">StorageClientFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/input.html" title="Input">Input</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMultitouch/index.html" title="BasicMultitouch">BasicMultitouch</a></div><ul><li><a href="/samples/BasicMultitouch/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMultitouch/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMultitouch/res/layout/layout_mainactivity.html" title="layout_mainactivity.xml">layout_mainactivity.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmultitouch">com.example.android.basicmultitouch/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.html" title="Pools.java">Pools.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/TouchDisplayView.html" title="TouchDisplayView.java">TouchDisplayView.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicGestureDetect/index.html" title="BasicGestureDetect">BasicGestureDetect</a></div><ul><li><a href="/samples/BasicGestureDetect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicgesturedetect">com.example.android.basicgesturedetect/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/BasicGestureDetectFragment.html" title="BasicGestureDetectFragment.java">BasicGestureDetectFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.html" title="GestureListener.java">GestureListener.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/media.html" title="Media">Media</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaRouter/index.html" title="BasicMediaRouter">BasicMediaRouter</a></div><ul><li><a href="/samples/BasicMediaRouter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/display.html" title="display.xml">display.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediarouter">com.example.android.basicmediarouter/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.html" title="SamplePresentation.java">SamplePresentation.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaDecoder/index.html" title="BasicMediaDecoder">BasicMediaDecoder</a></div><ul><li><a href="/samples/BasicMediaDecoder/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable/selector_play.html" title="selector_play.xml">selector_play.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/menu/action_menu.html" title="action_menu.xml">action_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="raw">raw/</a></div><ul><li>vid_bigbuckbunny.mp4</li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediadecoder">com.example.android.basicmediadecoder/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.basicmediadecoder/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.media">com.example.android.common.media/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/CameraHelper.html" title="CameraHelper.java">CameraHelper.java</a></li><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.html" title="MediaCodecWrapper.java">MediaCodecWrapper.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/security.html" title="Security">Security</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAndroidKeyStore/index.html" title="BasicAndroidKeyStore">BasicAndroidKeyStore</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicandroidkeystore">com.example.android.basicandroidkeystore/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.html" title="BasicAndroidKeyStoreFragment.java">BasicAndroidKeyStoreFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/SecurityConstants.html" title="SecurityConstants.java">SecurityConstants.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/testing.html" title="Testing">Testing</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/ActivityInstrumentation/index.html" title="ActivityInstrumentation">ActivityInstrumentation</a></div><ul><li><a href="/samples/ActivityInstrumentation/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.activityinstrumentation">com.example.android.activityinstrumentation/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.activityinstrumentation/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ui.html" title="UI">UI</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAccessibility/index.html" title="BasicAccessibility">BasicAccessibility</a></div><ul><li><a href="/samples/BasicAccessibility/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/partly_cloudy.html" title="partly_cloudy.png">partly_cloudy.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAccessibility/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicAccessibility/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicaccessibility">com.example.android.basicaccessibility/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/DialView.html" title="DialView.java">DialView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/HorizontalPaging/index.html" title="HorizontalPaging">HorizontalPaging</a></div><ul><li><a href="/samples/HorizontalPaging/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/HorizontalPaging/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/fragment_main_dummy.html" title="fragment_main_dummy.xml">fragment_main_dummy.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/styles.html" title="styles.xml">styles.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.horizontalpaging">com.example.android.horizontalpaging/</a></div><ul><li><a href="/samples/HorizontalPaging/src/com.example.android.horizontalpaging/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ShareActionProvider/index.html" title="ShareActionProvider">ShareActionProvider</a></div><ul><li><a href="/samples/ShareActionProvider/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ShareActionProvider/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_image.html" title="item_image.xml">item_image.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_text.html" title="item_text.xml">item_text.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ShareActionProvider/res/menu/main_menu.html" title="main_menu.xml">main_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.shareactionprovider">com.example.android.actionbarcompat.shareactionprovider/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="content">content/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.html" title="AssetProvider.java">AssetProvider.java</a></li><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.html" title="ContentItem.java">ContentItem.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Styled/index.html" title="Styled">Styled</a></div><ul><li><a href="/samples/Styled/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/Styled/res/drawable/pressed_background.html" title="pressed_background.xml">pressed_background.xml</a></li><li><a href="/samples/Styled/res/drawable/progress_horizontal.html" title="progress_horizontal.xml">progress_horizontal.xml</a></li><li><a href="/samples/Styled/res/drawable/selectable_background.html" title="selectable_background.xml">selectable_background.xml</a></li><li><a href="/samples/Styled/res/drawable/spinner_background_ab.html" title="spinner_background_ab.xml">spinner_background_ab.xml</a></li><li><a href="/samples/Styled/res/drawable/tab_indicator_ab.html" title="tab_indicator_ab.xml">tab_indicator_ab.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Styled/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Styled/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Styled/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Styled/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Styled/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/Styled/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Styled/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Styled/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/Styled/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.styled">com.example.android.actionbarcompat.styled/</a></div><ul><li><a href="/samples/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Basic/index.html" title="Basic">Basic</a></div><ul><li><a href="/samples/Basic/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Basic/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Basic/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Basic/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Basic/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Basic/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values/ids.html" title="ids.xml">ids.xml</a></li><li><a href="/samples/Basic/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Basic/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Basic/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.basic">com.example.android.actionbarcompat.basic/</a></div><ul><li><a href="/samples/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ImmersiveMode/index.html" title="ImmersiveMode">ImmersiveMode</a></div><ul><li><a href="/samples/ImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.immersivemode">com.example.android.immersivemode/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/ImmersiveModeFragment.html" title="ImmersiveModeFragment.java">ImmersiveModeFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextSwitcher/index.html" title="TextSwitcher">TextSwitcher</a></div><ul><li><a href="/samples/TextSwitcher/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextSwitcher/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextSwitcher/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextSwitcher/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextSwitcher/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textswitcher">com.example.android.textswitcher/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.textswitcher/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BorderlessButtons/index.html" title="BorderlessButtons">BorderlessButtons</a></div><ul><li><a href="/samples/BorderlessButtons/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BorderlessButtons/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BorderlessButtons/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.borderlessbuttons">com.example.android.borderlessbuttons/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.borderlessbuttons/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNotifications/index.html" title="BasicNotifications">BasicNotifications</a></div><ul><li><a href="/samples/BasicNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNotifications/res/layout/sample_layout.html" title="sample_layout.xml">sample_layout.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnotifications">com.example.android.basicnotifications/</a></div><ul><li><a href="/samples/BasicNotifications/src/com.example.android.basicnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AdvancedImmersiveMode/index.html" title="AdvancedImmersiveMode">AdvancedImmersiveMode</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.advancedimmersivemode">com.example.android.advancedimmersivemode/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.html" title="AdvancedImmersiveModeFragment.java">AdvancedImmersiveModeFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicImmersiveMode/index.html" title="BasicImmersiveMode">BasicImmersiveMode</a></div><ul><li><a href="/samples/BasicImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicimmersivemode">com.example.android.basicimmersivemode/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/BasicImmersiveModeFragment.html" title="BasicImmersiveModeFragment.java">BasicImmersiveModeFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomChoiceList/index.html" title="CustomChoiceList">CustomChoiceList</a></div><ul><li><a href="/samples/CustomChoiceList/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="color">color/</a></div><ul><li><a href="/samples/CustomChoiceList/res/color/hideable_text_color.html" title="hideable_text_color.xml">hideable_text_color.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable/ic_hideable_item.html" title="ic_hideable_item.xml">ic_hideable_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_checked.html" title="ic_hideable_item_checked.png">ic_hideable_item_checked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_unchecked.html" title="ic_hideable_item_unchecked.png">ic_hideable_item_unchecked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomChoiceList/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customchoicelist">com.example.android.customchoicelist/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/CheckableLinearLayout.html" title="CheckableLinearLayout.java">CheckableLinearLayout.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/DoneBar/index.html" title="DoneBar">DoneBar</a></div><ul><li><a href="/samples/DoneBar/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/sample_dashboard_item_background.9.html" title="sample_dashboard_item_background.9.png">sample_dashboard_item_background.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done.html" title="actionbar_custom_view_done.xml">actionbar_custom_view_done.xml</a></li><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done_cancel.html" title="actionbar_custom_view_done_cancel.xml">actionbar_custom_view_done_cancel.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_bar.html" title="activity_done_bar.xml">activity_done_bar.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_button.html" title="activity_done_button.xml">activity_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_sample_dashboard.html" title="activity_sample_dashboard.xml">activity_sample_dashboard.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_cancel_button.html" title="include_cancel_button.xml">include_cancel_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_done_button.html" title="include_done_button.xml">include_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/sample_dashboard_item.html" title="sample_dashboard_item.xml">sample_dashboard_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/DoneBar/res/menu/cancel.html" title="cancel.xml">cancel.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/DoneBar/res/values/activitycards-strings.html" title="activitycards-strings.xml">activitycards-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/DoneBar/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/DoneBar/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.donebar">com.example.android.donebar/</a></div><ul><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneBarActivity.html" title="DoneBarActivity.java">DoneBarActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneButtonActivity.html" title="DoneButtonActivity.java">DoneButtonActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ListPopupMenu/index.html" title="ListPopupMenu">ListPopupMenu</a></div><ul><li><a href="/samples/ListPopupMenu/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ListPopupMenu/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ListPopupMenu/res/menu/popup.html" title="popup.xml">popup.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.listpopupmenu">com.example.android.actionbarcompat.listpopupmenu/</a></div><ul><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.html" title="PopupListFragment.java">PopupListFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomNotifications/index.html" title="CustomNotifications">CustomNotifications</a></div><ul><li><a href="/samples/CustomNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot.html" title="robot.png">robot.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot_expanded.html" title="robot_expanded.png">robot_expanded.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification.html" title="notification.xml">notification.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification_expanded.html" title="notification_expanded.xml">notification_expanded.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v9">values-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-v9/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customnotifications">com.example.android.customnotifications/</a></div><ul><li><a href="/samples/CustomNotifications/src/com.example.android.customnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/views.html" title="Views">Views</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextLinkify/index.html" title="TextLinkify">TextLinkify</a></div><ul><li><a href="/samples/TextLinkify/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextLinkify/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextLinkify/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextLinkify/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextLinkify/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textlinkify">com.example.android.textlinkify/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.textlinkify/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li></ul>
+
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index a77cdfb..bc22416 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,5 +1,5 @@
 page.title=Android SDK
-page.tags="download"
+page.tags=download
 page.template=sdk
 header.hide=1
 page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 88fd7df..66c3034 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -74,12 +74,14 @@
 
 <div class="sidebox-wrapper">
 <div class="sidebox">
-<h2>Join the translation pilot</h2>
-<p>Google Play is offering <a
-href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">
-translation services</a> as part of a pilot program. If you are interested,
-sign up for the pilot program on the APK page in your Developer Console.</p>
-</div></div>
+<h2>App Translations in Google Play</h2>
+<p>Google Play <a href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">App 
+Translation Service</a> is available in the Developer Console to help you
+localize your app for a global user base. You can browse qualified vendors, get
+estimates, upload strings for translation, and then import the translations directly
+into your app.</p>
+</div>
+</div>
 
 <p>ADT Translation Manager Plugin is an Android SDK Tools plugin that helps
 you work with strings that you are localizing. It's designed to work
@@ -97,7 +99,8 @@
 localization works instantly.</p>
 
 <p>For more information about translation services in Google Play, see <a
-href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">Purchase professional translations through the Developer Console</a>.</p>
+href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">Purchase
+professional translations through the Developer Console</a>.</p>
 
 <p>To install the ADT Translation Manager Plugin follow these steps:</p>
 
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index f2fd79b..e83d1e0 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -1,5 +1,5 @@
 page.title=Getting Started with Android Studio
-page.tags="studio"
+page.tags=studio
 @jd:body
 
 
@@ -253,36 +253,36 @@
     <td>Windows</td>
     <td>
   <a onclick="return onDownload(this)" id="win-studio"
-      href="http://dl.google.com/android/studio/android-studio-bundle-132.883541-windows.exe">
-      android-studio-bundle-132.883541-windows.exe
+      href="http://dl.google.com/android/studio/install/0.3.2/android-studio-bundle-132.893413-windows.exe">
+      android-studio-bundle-132.893413-windows.exe
       </a>
     </td>
-    <td>448245492 bytes</td>
-    <td>ca5f5c4d21b4350ddf3bda7021a6ee5e</td>
+    <td>484345454 bytes</td>
+    <td>14cbf0109a822688f4e2f886c0b0c85a</td>
   </tr>
 
   <tr>
     <td><nobr>Mac OS X</nobr></td>
     <td>
   <a onclick="return onDownload(this)" id="mac-studio"
-    href="http://dl.google.com/android/studio/android-studio-bundle-132.883541-mac.dmg">
-    android-studio-bundle-132.883541-mac.dmg
+    href="http://dl.google.com/android/studio/install/0.3.2/android-studio-bundle-132.893413-mac.dmg">
+    android-studio-bundle-132.893413-mac.dmg
     </a>
     </td>
-    <td>427317993 bytes</td>
-    <td>67831af6e7896a0a146d43423fabb542</td>
+    <td>463332508 bytes</td>
+    <td>0cd4ac59864890f7de57314bcc7ea5aa</td>
   </tr>
 
   <tr>
     <td>Linux</td>
     <td>
   <a onclick="return onDownload(this)" id="linux-studio"
-    href="http://dl.google.com/android/studio/android-studio-bundle-132.883541-linux.tgz">
-    android-studio-bundle-132.883541-linux.tgz
+    href="http://dl.google.com/android/studio/install/0.3.2/android-studio-bundle-132.893413-linux.tgz">
+    android-studio-bundle-132.893413-linux.tgz
     </a>
     </td>
-    <td>451652493 bytes</td>
-    <td>7a6f9b12b2cd5321ab0818b51306e01c</td>
+    <td>487694946 bytes</td>
+    <td>9f1306100314b03ff5b691b94f154501</td>
   </tr>
   </table>
 
@@ -294,7 +294,8 @@
 
 <p>If you already have Android Studio installed, in most cases, you can upgrade to the latest
 version by installing a patch. From within Android Studio, select
-<strong>Help &gt; Check for updates</strong> to see whether an update is available.</p>
+<strong>Help &gt; Check for updates</strong> (on Mac, <strong>Android Studio &gt;
+Check for updates</strong>) to see whether an update is available.</p>
 
 <p>If an update is not available,
 follow the <a href="#Installing">installation instructions</a> below and replace your existing
@@ -423,7 +424,7 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
-      alt=""/>Android Studio v0.3.1</a> <em>(Oct 2013)</em>
+      alt=""/>Android Studio v0.3.2</a> <em>(Oct 2013)</em>
   </p>
 
   <div class="toggle-content-toggleme">
@@ -617,7 +618,7 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.3.1</span>"
+    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.3.2</span>"
         + "<br/> <span class='small'>for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
diff --git a/docs/html/sdk/win-usb.jd b/docs/html/sdk/win-usb.jd
index 5ca38c6..c287a0c 100644
--- a/docs/html/sdk/win-usb.jd
+++ b/docs/html/sdk/win-usb.jd
@@ -191,27 +191,19 @@
 </div>
 </div>
 
-<p>The Google USB Driver is for <strong>Windows only</strong> and provides the
-necessary drivers for the following devices:</p>
-  <ul>
-    <li>ADP1 / T-Mobile G1*</li>
-    <li>ADP2 / Google Ion / T-Mobile myTouch 3G*</li>
-    <li>Verizon Droid*</li>
-    <li>Nexus One</li>
-    <li>Nexus S</li>
-    <li>Nexus 4</li>
-    <li>Nexus 7</li>
-    <li>Nexus 10</li>
-  </ul>
-  <p>* <em>Or similar hardware on other carriers</em></p>
-
-  <p>All other devices require Windows drivers provided by the respective hardware manufacturer,
-  as listed in the <a href="{@docRoot}tools/extras/oem-usb.html">OEM USB Drivers</a> document.</p>
-
-  <p>The Galaxy Nexus driver is distributed by <a
+<p>The Google USB Driver is <strong>required for Windows only</strong> in order to perform
+<a href="{@docRoot}tools/help/adb.html">adb</a> debugging with any of
+the <strong>Google Nexus devices</strong>. The one exception is the
+Galaxy Nexus: the driver for Galaxy Nexus is distributed by <a
 href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a>
 (listed as model SCH-I515).</p>
 
+<p>Windows drivers for all other devices are provided by the respective hardware
+manufacturer, as listed in the <a href="{@docRoot}tools/extras/oem-usb.html">OEM USB Drivers</a>
+document.</p>
+
+
+
 <p class="note"><strong>Note:</strong>
 If you're developing on Mac OS X or Linux, then you <strong>do not</strong> need to install a USB
 driver. To start developing with your device, read
diff --git a/docs/html/tools/adk/adk.jd b/docs/html/tools/adk/adk.jd
index 1651747..7e75c11 100644
--- a/docs/html/tools/adk/adk.jd
+++ b/docs/html/tools/adk/adk.jd
@@ -1,5 +1,5 @@
 page.title=Accessory Development Kit 2011 Guide
-page.tags="adk"
+page.tags=adk
 @jd:body
 
   <div id="qv-wrapper">
diff --git a/docs/html/tools/adk/adk2.jd b/docs/html/tools/adk/adk2.jd
index c60e920..d69125a 100644
--- a/docs/html/tools/adk/adk2.jd
+++ b/docs/html/tools/adk/adk2.jd
@@ -1,5 +1,5 @@
 page.title=Accessory Development Kit 2012 Guide
-page.tags="adk"
+page.tags=adk
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/tools/adk/index.jd b/docs/html/tools/adk/index.jd
index e035115..e08748fc 100644
--- a/docs/html/tools/adk/index.jd
+++ b/docs/html/tools/adk/index.jd
@@ -1,5 +1,5 @@
 page.title=Accessory Development Kit
-page.tags="adk"
+page.tags=adk
 @jd:body
 
 <p>The Accessory Development Kit (ADK) is a reference implementation for hardware manufacturers and
diff --git a/docs/html/tools/debugging/debugging-memory.jd b/docs/html/tools/debugging/debugging-memory.jd
index 0454293..fccb67e 100644
--- a/docs/html/tools/debugging/debugging-memory.jd
+++ b/docs/html/tools/debugging/debugging-memory.jd
@@ -1,5 +1,5 @@
 page.title=Investigating Your RAM Usage
-page.tags="memory","OutOfMemoryError"
+page.tags=memory,OutOfMemoryError
 @jd:body
 
  <div id="qv-wrapper">
@@ -181,11 +181,18 @@
 
 <h2 id="ViewingAllocations">Viewing Overall Memory Allocations</h2>
 
-<p>For further analysis, you may want to observe how that your app's memory is
-divided between different categories, which you can do with the <code>adb meminfo</code> data.</p>
+<p>For further analysis, you may want to observe how your app's memory is
+divided between different types of RAM allocation with the
+following <a href="{@docRoot}tools/help/adb.html">adb</a> command:</p>
 
-<p>When talking about how much RAM your app is using with this data, the key metrics
-discussed below are:</p>
+<pre class="no-pretty-print">
+adb shell dumpsys meminfo &lt;package_name>
+</pre>
+
+<p>The output lists all of your app's current allocations, measured in kilobytes.</p>
+
+<p>When inspecting this information, you should be familiar with the
+following types of allocation:</p>
 
 <dl>
 <dt>Private (Clean and Dirty) RAM</dt>
@@ -210,15 +217,9 @@
 actual RAM weight of a process and for comparison against the RAM use of other processes and the
 total available RAM.</p>
 
-<p>You can look at the memory use of your app (measured in kilobytes) with the
-following adb command:</p>
-
-<pre class="no-pretty-print">
-adb shell dumpsys meminfo &lt;package_name>
-</pre>
 
 <p>For example, below is the the output for Gmail’s process on a tablet device. There is a lot of
-information here, but key points for discussion are highlighted in different colors.</p>
+information here, but key points for discussion are listed below.</p>
 
 <p class="note"><strong>Note:</strong> The information you see may vary slightly from what is shown
 here, as some details of the output differ across platform versions.</p>
@@ -491,4 +492,4 @@
 <p class="note"><strong>Tip:</strong> You can also perform the above steps by using the "monkey"
 test framework. For more information on running the monkey test framework, read the <a href=
 "{@docRoot}tools/help/monkeyrunner_concepts.html">monkeyrunner</a>
-documentation.</p>
\ No newline at end of file
+documentation.</p>
diff --git a/docs/html/tools/debugging/debugging-tracing.jd b/docs/html/tools/debugging/debugging-tracing.jd
index 8653da6..bd4afbc 100644
--- a/docs/html/tools/debugging/debugging-tracing.jd
+++ b/docs/html/tools/debugging/debugging-tracing.jd
@@ -38,8 +38,7 @@
   <h2 id="traceviewLayout">Traceview Layout</h2>
 
   <p>When you have a trace log file (generated by adding tracing code to your application or by DDMS),
-  you can have Traceview load the log files and display their data in a window visualizes your application
-  in two panels:</p>
+  you can load the log files in Traceview, which displays the log data in two panels:</p>
 
   <ul>
     <li>A <a href="#timelinepanel">timeline panel</a> -- describes when each thread and method
@@ -53,12 +52,11 @@
   
   <h3 id="timelinepanel">Timeline Panel</h3>
 
-  <p>The image below shows a close up of the timeline panel. Each thread&rsquo;s execution is shown
+  <p>Figure 1 shows a close up of the timeline panel. Each thread&rsquo;s execution is shown
   in its own row, with time increasing to the right. Each method is shown in another color (colors
   are reused in a round-robin fashion starting with the methods that have the most inclusive time).
   The thin lines underneath the first row show the extent (entry to exit) of all the calls to the
-  selected method. The method in this case is <code>LoadListener.nativeFinished()</code> and it was selected in
-  the profile view.</p>
+  selected method.</p>
 
   <img src="{@docRoot}images/traceview_timeline.png"
        alt="Traceview timeline panel"
@@ -94,23 +92,31 @@
   <p>There are two ways to generate trace logs:</p>
   <ul>
     <li>Include the {@link android.os.Debug} class in your code and call its
-  methods to start and stop logging of trace information to disk. This method is very precise because
-  you can specify in your code exactly where to start and stop logging trace data.</li>
-    <li>Use the method profiling feature of DDMS to generate trace logs. This method is less
-    precise since you do not modify code, but rather specify when to start and stop logging with
-    a DDMS. Although you have less control on exactly where the data is logged, this method is useful 
-    if you don't have access to the application's code, or if you do not need the precision of the first method.
+  methods such as {@link android.os.Debug#startMethodTracing()} and {@link
+  android.os.Debug#stopMethodTracing()}, to start and stop logging of trace information to disk.
+  This option is very precise because
+  you can specify exactly where to start and stop logging trace data in your code.</li>
+    <li>Use the method profiling feature of DDMS to generate trace logs. This option is less
+    precise because you do not modify code, but rather specify when to start and stop logging with
+    DDMS. Although you have less control on exactly where logging starts and stops,
+    this option is useful if you don't have access to the application's code, or if you do
+    not need precise log timing.
     </li>
   </ul>
   
   <p>Before you start generating trace logs, be aware of the following restrictions:</p>
   <ul>
-    <li>If you are using the {@link android.os.Debug} class, your device or emulator must have an SD card
-     and your application must have permission to write to the SD card. </li>
-    <li>If you are using DDMS, Android 2.1 and earlier devices must
+    <li>If you are using the {@link android.os.Debug} class,
+     your application must have permission to write to external storage
+     ({@link android.Manifest.permission#READ_EXTERNAL_STORAGE}). </li>
+    <li>If you are using DDMS:
+      <ul>
+        <li>Android 2.1 and earlier devices must
     have an SD card present and your application must have permission to write to the SD card.
-    <li>If you are using DDMS, Android 2.2 and later devices do not need an SD card. The trace log files are 
+        <li>Android 2.2 and later devices do not need an SD card. The trace log files are
     streamed directly to your development machine.</li>
+      </ul>
+    </li>
   </ul>
   
   <p>This document focuses on using the {@link android.os.Debug} class to generate trace data.  For more information on using DDMS
@@ -134,22 +140,22 @@
     Debug.stopMethodTracing();
 </pre>
 
-  <p>When your application calls startMethodTracing(), the system creates a file called
+  <p>When your application calls {@link android.os.Debug#startMethodTracing() startMethodTracing()},
+  the system creates a file called
   <code>&lt;trace-base-name&gt;.trace</code>. This contains the binary method trace data and a
   mapping table with thread and method names.</p>
 
   <p>The system then begins buffering the generated trace data, until your application calls
-  stopMethodTracing(), at which time it writes the buffered data to the output file. If the system
-  reaches the maximum buffer size before stopMethodTracing() is called, the system stops tracing
+  {@link android.os.Debug#stopMethodTracing() stopMethodTracing()}, at which time it writes
+  the buffered data to the output file. If the system
+  reaches the maximum buffer size before you call {@link android.os.Debug#stopMethodTracing()
+  stopMethodTracing()}, the system stops tracing
   and sends a notification to the console.</p>
 
-  <p>Interpreted code will run more slowly when profiling is enabled. Don't try to generate
-  absolute timings from the profiler results (i.e. "function X takes 2.5 seconds to run"). The
+  <p>Interpreted code runs more slowly when profiling is enabled. Don't try to generate
+  absolute timings from the profiler results (such as, "function X takes 2.5 seconds to run"). The
   times are only useful in relation to other profile output, so you can see if changes have made
-  the code faster or slower.</p>
-
-  <p>When using the Android emulator, you must specify an SD card when you create your AVD because the trace files
-  are written to the SD card. Your application must have permission to write to the SD card as well.
+  the code faster or slower relative to a previous profiling run.</p>
 
   <h2 id="copyingfiles">Copying Trace Files to a Host Machine</h2>
 
@@ -189,7 +195,7 @@
       "{@docRoot}images/tracedump.png"
           width="485"
           height="401" />
-       <p class="image-caption"><strong>Figure 3.</strong> Screenshot of dmtracedump</p>
+       <p class="img-caption"><strong>Figure 3.</strong> Screenshot of dmtracedump</p>
 
       <p>For each node, dmtracedump shows <code>&lt;ref&gt;
       <em>callname</em> (&lt;inc-ms&gt;, &lt;exc-ms&gt;,&lt;numcalls&gt;)</code>, where</p>
diff --git a/docs/html/tools/help/adb.jd b/docs/html/tools/help/adb.jd
index 3002d60..1850123 100644
--- a/docs/html/tools/help/adb.jd
+++ b/docs/html/tools/help/adb.jd
@@ -1,7 +1,7 @@
 page.title=Android Debug Bridge
 parent.title=Tools
 parent.link=index.html
-page.tags="adb"
+page.tags=adb
 @jd:body
 
 <div id="qv-wrapper">
@@ -1130,10 +1130,11 @@
 
 <h3 id="screenrecord">Recording a device screen</h3>
 
-<p>The {@code screenrecord} command is a shell utility for recording the display of a device as you
-  use it. The utility records screen activity to an MPEG-4 file, which you can then download and use
-  as part of a video presentation. This utility is useful for developers who want to create
-  promotional or training videos without using a separate recording device.</p>
+<p>The {@code screenrecord} command is a shell utility for recording the display of devices
+  running Android 4.4 (API level 19) and higher. The utility records screen activity to an MPEG-4
+  file, which you can then download and use as part of a video presentation. This utility is useful
+  for developers who want to create promotional or training videos without using a separate
+  recording device.</p>
 
 <p>To use the {@code screenrecord} from the command line, type the following:
 
diff --git a/docs/html/tools/help/adt.jd b/docs/html/tools/help/adt.jd
index 4dac574..1bb3015 100644
--- a/docs/html/tools/help/adt.jd
+++ b/docs/html/tools/help/adt.jd
@@ -1,5 +1,5 @@
 page.title=Android Developer Tools
-page.tags="adt"
+page.tags=adt
 @jd:body
 
   <div id="qv-wrapper">
diff --git a/docs/html/tools/help/draw9patch.jd b/docs/html/tools/help/draw9patch.jd
index ebf2c6c..859b1cf 100644
--- a/docs/html/tools/help/draw9patch.jd
+++ b/docs/html/tools/help/draw9patch.jd
@@ -1,5 +1,5 @@
 page.title=Draw 9-patch
-page.tags="NinePatch"
+page.tags=NinePatch
 @jd:body
 
 <p>The Draw 9-patch tool allows you to easily create a 
diff --git a/docs/html/tools/help/proguard.jd b/docs/html/tools/help/proguard.jd
index be0b8dc..3ba7db2 100644
--- a/docs/html/tools/help/proguard.jd
+++ b/docs/html/tools/help/proguard.jd
@@ -61,6 +61,12 @@
   <p>To enable ProGuard so that it runs as part of an Ant or Eclipse build, set the
   <code>proguard.config</code> property in the <code>&lt;project_root&gt;/project.properties</code>
   file. The path can be an absolute path or a path relative to the project's root.</p>
+
+<p class="note"><strong>Note:</strong> When using Android Studio, you must add Proguard
+to your <code>gradle.build</code> file's build types. For more information, see the
+<a href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Running-ProGuard"
+>Gradle Plugin User Guide</a>.
+
 <p>If you left the <code>proguard.cfg</code> file in its default location (the project's root directory),
 you can specify its location like this:</p>
 <pre class="no-pretty-print">
diff --git a/docs/html/tools/samples/index.jd b/docs/html/tools/samples/index.jd
index 76ba37a..a0d11e9 100644
--- a/docs/html/tools/samples/index.jd
+++ b/docs/html/tools/samples/index.jd
@@ -1,5 +1,5 @@
 page.title=Samples
-page.tags="example","code"
+page.tags=example,code
 @jd:body
 
 <p>To help you understand some fundamental Android APIs and coding practices, a variety of sample
@@ -29,4 +29,4 @@
   <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level</a>.</p>
 
 <p>You can easily create new Android projects with the downloaded samples, modify them
-if you'd like, and then run them on an emulator or device.</p>
\ No newline at end of file
+if you'd like, and then run them on an emulator or device.</p>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index a418f90..87f8a87 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -2822,7 +2822,7 @@
   <p>Before you get started make sure that you have downloaded the latest <a href=
   "{@docRoot}sdk/index.html">Android SDK</a> and upgraded your applications and environment as
   needed. The NDK is compatible with older platform versions but not older versions of the SDK tools.
-  Also, take a moment to review the <a href="{@docRoot}tools/sdk/ndk/overview.html#reqs">System and
+  Also, take a moment to review the <a href="#Reqs">System and
 Software Requirements</a>
   for the NDK, if you haven't already.</p>
 
diff --git a/docs/html/tools/support-library/setup.jd b/docs/html/tools/support-library/setup.jd
index 73d9468..2d2065a 100644
--- a/docs/html/tools/support-library/setup.jd
+++ b/docs/html/tools/support-library/setup.jd
@@ -180,8 +180,8 @@
         file and select <strong>Build Path &gt; Add to Build Path</strong>. For example, when
         creating the the v7 appcompat project, add both the {@code android-support-v4.jar} and
         {@code android-support-v7-appcompat.jar} files to the build path.</li>
-      <li>Right-click the project and select <strong>Build Path &gt; Configure Build Path</strong>.
-        </li>
+      <li>Right-click the library project folder and select <strong>Build Path &gt; Configure
+        Build Path</strong>.</li>
       <li>In the <strong>Order and Export</strong> tab, check the <code>.jar</code> files you just
         added to the build path, so they are available to projects that depend on this library
         project. For example, the {@code appcompat} project requires you to export both the
@@ -197,12 +197,13 @@
 
 <p>Add the library to your application project:</p>
   <ol>
-    <li>In the Project Explorer, right-click your project and select <strong>Properties</strong>.
-    <li>In the Library pane, click <strong>Add</strong>.
+    <li>In the Project Explorer, right-click your project and select <strong>Properties</strong>.</li>
+    <li>In the category panel on the left side of the dialog, select <strong>Android</strong>.</li>
+    <li>In the Library pane, click the <strong>Add</strong> button.</li>
     <li>Select the library project and click <strong>OK</strong>. For example, the
       {@code appcompat} project should be listed as <strong>android-support-v7-appcompat</strong>.
       </li>
-    <li>In the properties window, click <strong>OK</strong>.
+    <li>In the properties window, click <strong>OK</strong>.</li>
   </ol>
 
   </div>
diff --git a/docs/html/training/accessibility/index.jd b/docs/html/training/accessibility/index.jd
index 0af1d87..ea54dc4 100644
--- a/docs/html/training/accessibility/index.jd
+++ b/docs/html/training/accessibility/index.jd
@@ -1,5 +1,5 @@
 page.title=Implementing Accessibility
-page.tags="navigation","input"
+page.tags=navigation,input
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/activity-testing/index.jd b/docs/html/training/activity-testing/index.jd
index ddede71..b9542b6 100644
--- a/docs/html/training/activity-testing/index.jd
+++ b/docs/html/training/activity-testing/index.jd
@@ -1,5 +1,5 @@
 page.title=Testing Your Android Activity
-page.tags="testing"
+page.tags=testing
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/animation/index.jd b/docs/html/training/animation/index.jd
index b6940f8..4f37788 100644
--- a/docs/html/training/animation/index.jd
+++ b/docs/html/training/animation/index.jd
@@ -1,5 +1,5 @@
 page.title=Adding Animations
-page.tags="Animator","views","layout","user interface"
+page.tags=Animator,views,layout,user interface
 trainingnavtop=true
 startpage=true
 
@@ -84,4 +84,4 @@
       <dd>
         Learn how to enable built-in animations when adding, removing, or updating child views in a layout.
       </dd>
-    </dl>
\ No newline at end of file
+    </dl>
diff --git a/docs/html/training/articles/memory.jd b/docs/html/training/articles/memory.jd
index cdc0cd4..f15af68 100644
--- a/docs/html/training/articles/memory.jd
+++ b/docs/html/training/articles/memory.jd
@@ -1,5 +1,5 @@
 page.title=Managing Your App's Memory
-page.tags="ram","low memory","OutOfMemoryError","onTrimMemory"
+page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
 page.article=true
 @jd:body
 
diff --git a/docs/html/training/articles/perf-anr.jd b/docs/html/training/articles/perf-anr.jd
index 87cfc1c..b32cc4f 100644
--- a/docs/html/training/articles/perf-anr.jd
+++ b/docs/html/training/articles/perf-anr.jd
@@ -1,5 +1,5 @@
 page.title=Keeping Your App Responsive
-page.tags="threads","asynctask"
+page.tags=threads,asynctask
 
 page.article=true
 @jd:body
diff --git a/docs/html/training/articles/perf-jni.jd b/docs/html/training/articles/perf-jni.jd
index 9f880ec..435d231 100644
--- a/docs/html/training/articles/perf-jni.jd
+++ b/docs/html/training/articles/perf-jni.jd
@@ -1,5 +1,5 @@
 page.title=JNI Tips
-page.tags="ndk","native"
+page.tags=ndk,native
 
 page.article=true
 @jd:body
diff --git a/docs/html/training/articles/security-ssl.jd b/docs/html/training/articles/security-ssl.jd
index f52865a..0639fb0 100644
--- a/docs/html/training/articles/security-ssl.jd
+++ b/docs/html/training/articles/security-ssl.jd
@@ -1,5 +1,5 @@
 page.title=Security with HTTPS and SSL
-page.tags="network","certificates"
+page.tags=network,certificates
 
 page.article=true
 @jd:body
diff --git a/docs/html/training/articles/smp.jd b/docs/html/training/articles/smp.jd
index 7240eec..0b45987 100644
--- a/docs/html/training/articles/smp.jd
+++ b/docs/html/training/articles/smp.jd
@@ -1,5 +1,5 @@
 page.title=SMP Primer for Android
-page.tags="ndk","native"
+page.tags=ndk,native
 
 page.article=true
 @jd:body
diff --git a/docs/html/training/backward-compatible-ui/index.jd b/docs/html/training/backward-compatible-ui/index.jd
index 4baa55c..c8b6ecc 100644
--- a/docs/html/training/backward-compatible-ui/index.jd
+++ b/docs/html/training/backward-compatible-ui/index.jd
@@ -1,5 +1,5 @@
 page.title=Creating Backward-Compatible UIs
-page.tags="widgets","support"
+page.tags=widgets,support
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/actionbar/index.jd b/docs/html/training/basics/actionbar/index.jd
index f0de758..0303043 100644
--- a/docs/html/training/basics/actionbar/index.jd
+++ b/docs/html/training/basics/actionbar/index.jd
@@ -1,5 +1,5 @@
 page.title=Adding the Action Bar
-page.tags="actionbar"
+page.tags=actionbar
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/data-storage/index.jd b/docs/html/training/basics/data-storage/index.jd
index 4ccad75..fc0c8b5 100644
--- a/docs/html/training/basics/data-storage/index.jd
+++ b/docs/html/training/basics/data-storage/index.jd
@@ -1,5 +1,5 @@
 page.title=Saving Data
-page.tags="data storage","files","sql","database","preferences"
+page.tags=data storage,files,sql,database,preferences
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/fragments/index.jd b/docs/html/training/basics/fragments/index.jd
index 987decf..e78b694 100644
--- a/docs/html/training/basics/fragments/index.jd
+++ b/docs/html/training/basics/fragments/index.jd
@@ -1,5 +1,5 @@
 page.title=Building a Dynamic UI with Fragments
-page.tags="fragments", "user interface", "support library"
+page.tags=fragments,user interface,support library
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/fragments/support-lib.jd b/docs/html/training/basics/fragments/support-lib.jd
index d949267..1d538af 100644
--- a/docs/html/training/basics/fragments/support-lib.jd
+++ b/docs/html/training/basics/fragments/support-lib.jd
@@ -1,5 +1,5 @@
 page.title=Using the Support Library
-page.tags="support library"
+page.tags=support library
 
 trainingnavtop=true
 
diff --git a/docs/html/training/basics/intents/index.jd b/docs/html/training/basics/intents/index.jd
index 59ba11f..aa0232a 100644
--- a/docs/html/training/basics/intents/index.jd
+++ b/docs/html/training/basics/intents/index.jd
@@ -1,5 +1,5 @@
 page.title=Interacting with Other Apps
-page.tags="intents","activity"
+page.tags=intents,activity
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/network-ops/index.jd b/docs/html/training/basics/network-ops/index.jd
index cb3a390..89ab539 100644
--- a/docs/html/training/basics/network-ops/index.jd
+++ b/docs/html/training/basics/network-ops/index.jd
@@ -1,5 +1,5 @@
 page.title=Performing Network Operations
-page.tags="network","wireless"
+page.tags=network,wireless
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/supporting-devices/index.jd b/docs/html/training/basics/supporting-devices/index.jd
index 1e3eb42..6f339f4 100644
--- a/docs/html/training/basics/supporting-devices/index.jd
+++ b/docs/html/training/basics/supporting-devices/index.jd
@@ -1,5 +1,5 @@
 page.title=Supporting Different Devices
-page.tags="resources","screens","versions","localization"
+page.tags=resources,screens,versions,localization
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 130848e..5a1507c 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -1,6 +1,6 @@
 page.title=Supporting Different Languages
 parent.title=Supporting Different Devices
-page.tags="localizing","localization","resources", "formats", "l10n"
+page.tags=localizing,localization,resources,formats,l10n
 parent.link=index.html
 
 trainingnavtop=true
diff --git a/docs/html/training/beam-files/index.jd b/docs/html/training/beam-files/index.jd
index e4bac2e..910fa38 100644
--- a/docs/html/training/beam-files/index.jd
+++ b/docs/html/training/beam-files/index.jd
@@ -1,5 +1,5 @@
 page.title=Sharing Files with NFC
-page.tags="NfcAdapter","Android Beam","share","file transfer"
+page.tags=NfcAdapter,Android Beam,share,file transfer
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/beam-files/send-files.jd b/docs/html/training/beam-files/send-files.jd
index 917b87f..40f706f 100644
--- a/docs/html/training/beam-files/send-files.jd
+++ b/docs/html/training/beam-files/send-files.jd
@@ -139,7 +139,7 @@
 &lt;uses-feature android:name="android.hardware.nfc" android:required="false" /&gt;</pre>
 <p>
     If you set the attribute
-    <code><a href="guide/topics/manifest/uses-feature-element.html#required"
+    <code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#required"
     >android:required</a>="false"</code>, you must test for NFC support and Android Beam file
     transfer support in code.
 </p>
diff --git a/docs/html/training/camera/index.jd b/docs/html/training/camera/index.jd
index d6305d6..5560649 100644
--- a/docs/html/training/camera/index.jd
+++ b/docs/html/training/camera/index.jd
@@ -1,5 +1,5 @@
 page.title=Capturing Photos
-page.tags="camera","video","picture"
+page.tags=camera,video,picture
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/cloudsave/conflict-res.jd b/docs/html/training/cloudsave/conflict-res.jd
index 0ff50e2..73e75db 100644
--- a/docs/html/training/cloudsave/conflict-res.jd
+++ b/docs/html/training/cloudsave/conflict-res.jd
@@ -1,5 +1,5 @@
 page.title=Resolving Cloud Save Conflicts
-page.tags="cloud"
+page.tags=cloud
 
 page.article=true
 @jd:body
@@ -594,4 +594,4 @@
 limited. Depending on your implementation, it might make sense to store the
 timestamp for when each entry in the dictionary was modified. When you detect that a
 given entry has not been modified in the last several weeks or months, it is
-probably safe to transfer the coins into another entry and delete the old entry.</p>
\ No newline at end of file
+probably safe to transfer the coins into another entry and delete the old entry.</p>
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
index 55b275b..eb7df3d 100644
--- a/docs/html/training/cloudsync/index.jd
+++ b/docs/html/training/cloudsync/index.jd
@@ -1,5 +1,5 @@
 page.title=Syncing to the Cloud
-page.tags="cloud","sync","backup"
+page.tags=cloud,sync,backup
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/connect-devices-wirelessly/index.jd b/docs/html/training/connect-devices-wirelessly/index.jd
index db79abe..2da4e38 100644
--- a/docs/html/training/connect-devices-wirelessly/index.jd
+++ b/docs/html/training/connect-devices-wirelessly/index.jd
@@ -1,5 +1,5 @@
 page.title=Connecting Devices Wirelessly
-page.tags="wifi","network","wireless"
+page.tags=wifi,network,wireless
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/custom-views/create-view.jd b/docs/html/training/custom-views/create-view.jd
index b849cb3..11be85f 100644
--- a/docs/html/training/custom-views/create-view.jd
+++ b/docs/html/training/custom-views/create-view.jd
@@ -22,7 +22,7 @@
 
         <h2>You should also read</h2>
         <ul>
-            <li><a href="{@docRoot}/guide/topics/ui/custom-components.html">Custom Components</a>
+            <li><a href="{@docRoot}guide/topics/ui/custom-components.html">Custom Components</a>
             </li>
         </ul>
 <h2>Try it out</h2>
diff --git a/docs/html/training/custom-views/index.jd b/docs/html/training/custom-views/index.jd
index 1c09e66..87cd0b0 100644
--- a/docs/html/training/custom-views/index.jd
+++ b/docs/html/training/custom-views/index.jd
@@ -1,5 +1,5 @@
 page.title=Creating Custom Views
-page.tags="widgets","ui","layout"
+page.tags=widgets,ui,layout
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd
index 1f44fa8..5521870 100644
--- a/docs/html/training/displaying-bitmaps/index.jd
+++ b/docs/html/training/displaying-bitmaps/index.jd
@@ -1,5 +1,5 @@
 page.title=Displaying Bitmaps Efficiently
-page.tags="bitmaps","images","graphics"
+page.tags=bitmaps,images,graphics
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/displaying-bitmaps/manage-memory.jd b/docs/html/training/displaying-bitmaps/manage-memory.jd
index 0e1279e..7f2b4c5 100644
--- a/docs/html/training/displaying-bitmaps/manage-memory.jd
+++ b/docs/html/training/displaying-bitmaps/manage-memory.jd
@@ -160,13 +160,14 @@
 in a {@link java.util.HashSet}, for possible reuse later with
 {@link android.graphics.BitmapFactory.Options#inBitmap}:
 
-<pre>HashSet&lt;SoftReference&lt;Bitmap&gt;&gt; mReusableBitmaps;
+<pre>Set&lt;SoftReference&lt;Bitmap&gt;&gt; mReusableBitmaps;
 private LruCache&lt;String, BitmapDrawable&gt; mMemoryCache;
 
-// If you're running on Honeycomb or newer, create
-// a HashSet of references to reusable bitmaps.
+// If you're running on Honeycomb or newer, create a
+// synchronized HashSet of references to reusable bitmaps.
 if (Utils.hasHoneycomb()) {
-    mReusableBitmaps = new HashSet&lt;SoftReference&lt;Bitmap&gt;&gt;();
+    mReusableBitmaps =
+            Collections.synchronizedSet(new HashSet&lt;SoftReference&lt;Bitmap&gt;&gt;());
 }
 
 mMemoryCache = new LruCache&lt;String, BitmapDrawable&gt;(mCacheParams.memCacheSize) {
@@ -243,25 +244,27 @@
         Bitmap bitmap = null;
 
     if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
-        final Iterator&lt;SoftReference&lt;Bitmap&gt;&gt; iterator
-                = mReusableBitmaps.iterator();
-        Bitmap item;
+        synchronized (mReusableBitmaps) {
+            final Iterator&lt;SoftReference&lt;Bitmap&gt;&gt; iterator
+                    = mReusableBitmaps.iterator();
+            Bitmap item;
 
-        while (iterator.hasNext()) {
-            item = iterator.next().get();
+            while (iterator.hasNext()) {
+                item = iterator.next().get();
 
-            if (null != item && item.isMutable()) {
-                // Check to see it the item can be used for inBitmap.
-                if (canUseForInBitmap(item, options)) {
-                    bitmap = item;
+                if (null != item && item.isMutable()) {
+                    // Check to see it the item can be used for inBitmap.
+                    if (canUseForInBitmap(item, options)) {
+                        bitmap = item;
 
-                    // Remove from reusable set so it can't be used again.
+                        // Remove from reusable set so it can't be used again.
+                        iterator.remove();
+                        break;
+                    }
+                } else {
+                    // Remove from the set if the reference has been cleared.
                     iterator.remove();
-                    break;
                 }
-            } else {
-                // Remove from the set if the reference has been cleared.
-                iterator.remove();
             }
         }
     }
diff --git a/docs/html/training/efficient-downloads/index.jd b/docs/html/training/efficient-downloads/index.jd
index 2ab93ae..d9d7ef0 100644
--- a/docs/html/training/efficient-downloads/index.jd
+++ b/docs/html/training/efficient-downloads/index.jd
@@ -1,5 +1,5 @@
 page.title=Transferring Data Without Draining the Battery
-page.tags="battery","network","wireless"
+page.tags=battery,network,wireless
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/enterprise/index.jd b/docs/html/training/enterprise/index.jd
index ac1b565..2926f71 100644
--- a/docs/html/training/enterprise/index.jd
+++ b/docs/html/training/enterprise/index.jd
@@ -1,5 +1,5 @@
 page.title=Developing for Enterprise
-page.tags="policy","privacy"
+page.tags=policy,privacy
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/gestures/index.jd b/docs/html/training/gestures/index.jd
index 9d21b08..260cfff 100644
--- a/docs/html/training/gestures/index.jd
+++ b/docs/html/training/gestures/index.jd
@@ -1,5 +1,5 @@
 page.title=Using Touch Gestures
-page.tags="input","navigation","gesturedetector","scroller"
+page.tags=input,navigation,gesturedetector,scroller
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/gestures/scroll.jd b/docs/html/training/gestures/scroll.jd
index 09fcc4e..4b82d69 100644
--- a/docs/html/training/gestures/scroll.jd
+++ b/docs/html/training/gestures/scroll.jd
@@ -95,7 +95,7 @@
 finger across the touch screen. Simple dragging is often implemented by overriding 
 {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} in 
 {@link android.view.GestureDetector.OnGestureListener}. For more discussion of dragging, see 
-<a href="dragging.html">Dragging and Scaling</a>.</li>
+<a href="scale.html">Dragging and Scaling</a>.</li>
 
     <li><strong>Flinging</strong> is the type of scrolling that occurs when a user 
 drags and lifts her finger quickly. After the user lifts her finger, you generally 
diff --git a/docs/html/training/graphics/opengl/draw.jd b/docs/html/training/graphics/opengl/draw.jd
index 156ff70..ba00627 100644
--- a/docs/html/training/graphics/opengl/draw.jd
+++ b/docs/html/training/graphics/opengl/draw.jd
@@ -122,7 +122,7 @@
 get created once and then cached for later use.</p>
 
 <pre>
-public Triangle() {
+public class Triangle() {
     ...
 
     int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
diff --git a/docs/html/training/graphics/opengl/environment.jd b/docs/html/training/graphics/opengl/environment.jd
index e1e2c8a..77faabf 100644
--- a/docs/html/training/graphics/opengl/environment.jd
+++ b/docs/html/training/graphics/opengl/environment.jd
@@ -92,7 +92,7 @@
 {@link android.opengl.GLSurfaceView} as its primary view:</p>
 
 <pre>
-public class OpenGLES20 extends Activity {
+public class OpenGLES20Activity extends Activity {
 
     private GLSurfaceView mGLView;
 
@@ -190,11 +190,11 @@
 gray background in the {@link android.opengl.GLSurfaceView}:</p>
 
 <pre>
-public class MyGL20Renderer implements GLSurfaceView.Renderer {
+public class MyGLRenderer implements GLSurfaceView.Renderer {
 
     public void onSurfaceCreated(GL10 unused, EGLConfig config) {
         // Set the background frame color
-        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
     }
 
     public void onDrawFrame(GL10 unused) {
diff --git a/docs/html/training/graphics/opengl/index.jd b/docs/html/training/graphics/opengl/index.jd
index cf33d80..3549f95 100644
--- a/docs/html/training/graphics/opengl/index.jd
+++ b/docs/html/training/graphics/opengl/index.jd
@@ -1,5 +1,5 @@
 page.title=Displaying Graphics with OpenGL ES
-page=tags="open gl","graphics"
+page.tags=open gl,graphics
 trainingnavtop=true
 
 @jd:body
diff --git a/docs/html/training/graphics/opengl/motion.jd b/docs/html/training/graphics/opengl/motion.jd
index af70de0..fbcdd7f 100644
--- a/docs/html/training/graphics/opengl/motion.jd
+++ b/docs/html/training/graphics/opengl/motion.jd
@@ -53,16 +53,20 @@
 private float[] mRotationMatrix = new float[16];
 public void onDrawFrame(GL10 gl) {
     ...
+    float[] scratch = new float[16];
+
     // Create a rotation transformation for the triangle
     long time = SystemClock.uptimeMillis() % 4000L;
     float angle = 0.090f * ((int) time);
     Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);
 
     // Combine the rotation matrix with the projection and camera view
-    Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
+    // Note that the mMVPMatrix factor *must be first* in order
+    // for the matrix multiplication product to be correct.
+    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
 
     // Draw triangle
-    mTriangle.draw(mMVPMatrix);
+    mTriangle.draw(scratch);
 }
 </pre>
 
@@ -82,8 +86,9 @@
 <pre>
 public MyGLSurfaceView(Context context) {
     ...
-    // Render the view only when there is a change in the drawing data
-    //setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); // comment out for auto-rotation
+    // Render the view only when there is a change in the drawing data.
+    // To allow the triangle to rotate automatically, this line is commented out:
+    <strong>//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);</strong>
 }
 </pre>
 
diff --git a/docs/html/training/graphics/opengl/projection.jd b/docs/html/training/graphics/opengl/projection.jd
index 2a91093..b09e74c 100644
--- a/docs/html/training/graphics/opengl/projection.jd
+++ b/docs/html/training/graphics/opengl/projection.jd
@@ -79,12 +79,12 @@
 
     // this projection matrix is applied to object coordinates
     // in the onDrawFrame() method
-    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
+    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
 }
 </pre>
 
-<p>This code populates a projection matrix, {@code mProjMatrix} which you can then combine with a
-camera view transformation in the {@link android.opengl.GLSurfaceView.Renderer#onDrawFrame
+<p>This code populates a projection matrix, {@code mProjectionMatrix} which you can then combine
+with a camera view transformation in the {@link android.opengl.GLSurfaceView.Renderer#onDrawFrame
 onDrawFrame()} method, which is shown in the next section.</p>
 
 <p class="note"><strong>Note:</strong> Just applying a projection transformation to your
@@ -104,12 +104,11 @@
 &#64;Override
 public void onDrawFrame(GL10 unused) {
     ...
-
     // Set the camera position (View matrix)
-    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
+    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
 
     // Calculate the projection and view transformation
-    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
+    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
 
     // Draw shape
     mTriangle.draw(mMVPMatrix);
@@ -130,7 +129,7 @@
     // get handle to shape's transformation matrix
     mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
 
-    // Apply the projection and view transformation
+    // Pass the projection and view transformation to the shader
     GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
 
     // Draw the triangle
@@ -139,7 +138,7 @@
 }
 </pre>
 
-<p>Once you have correctly calulated and applied the projection and camera view transformations,
+<p>Once you have correctly calculated and applied the projection and camera view transformations,
 your graphic objects are drawn in correct proportions and should look like this:</p>
 
 
diff --git a/docs/html/training/graphics/opengl/shapes.jd b/docs/html/training/graphics/opengl/shapes.jd
index 98381cc..b960bb7 100644
--- a/docs/html/training/graphics/opengl/shapes.jd
+++ b/docs/html/training/graphics/opengl/shapes.jd
@@ -50,16 +50,16 @@
 OpenGL ES graphics pipeline for processing.</p>
 
 <pre>
-class Triangle {
+public class Triangle {
 
     private FloatBuffer vertexBuffer;
 
     // number of coordinates per vertex in this array
     static final int COORDS_PER_VERTEX = 3;
-    static float triangleCoords[] = { // in counterclockwise order:
-         0.0f,  0.622008459f, 0.0f,   // top
-        -0.5f, -0.311004243f, 0.0f,   // bottom left
-         0.5f, -0.311004243f, 0.0f    // bottom right
+    static float triangleCoords[] = {   // in counterclockwise order:
+             0.0f,  0.622008459f, 0.0f, // top
+            -0.5f, -0.311004243f, 0.0f, // bottom left
+             0.5f, -0.311004243f, 0.0f  // bottom right
     };
 
     // Set color with red, green, blue and alpha (opacity) values
@@ -112,17 +112,18 @@
 OpenGL ES graphics pipeline how to draw these vertices. Here’s the code for this shape:</p>
 
 <pre>
-class Square {
+public class Square {
 
     private FloatBuffer vertexBuffer;
     private ShortBuffer drawListBuffer;
 
     // number of coordinates per vertex in this array
     static final int COORDS_PER_VERTEX = 3;
-    static float squareCoords[] = { -0.5f,  0.5f, 0.0f,   // top left
-                                    -0.5f, -0.5f, 0.0f,   // bottom left
-                                     0.5f, -0.5f, 0.0f,   // bottom right
-                                     0.5f,  0.5f, 0.0f }; // top right
+    static float squareCoords[] = {
+            -0.5f,  0.5f, 0.0f,   // top left
+            -0.5f, -0.5f, 0.0f,   // bottom left
+             0.5f, -0.5f, 0.0f,   // bottom right
+             0.5f,  0.5f, 0.0f }; // top right
 
     private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
 
diff --git a/docs/html/training/graphics/opengl/touch.jd b/docs/html/training/graphics/opengl/touch.jd
index c058a59..4c9f0c7 100644
--- a/docs/html/training/graphics/opengl/touch.jd
+++ b/docs/html/training/graphics/opengl/touch.jd
@@ -75,7 +75,9 @@
               dy = dy * -1 ;
             }
 
-            mRenderer.mAngle += (dx + dy) * TOUCH_SCALE_FACTOR;  // = 180.0f / 320
+            mRenderer.setAngle(
+                    mRenderer.getAngle() +
+                    ((dx + dy) * TOUCH_SCALE_FACTOR);  // = 180.0f / 320
             requestRender();
     }
 
@@ -123,16 +125,20 @@
 <pre>
 public void onDrawFrame(GL10 gl) {
     ...
+    float[] scratch = new float[16];
+
     // Create a rotation for the triangle
     // long time = SystemClock.uptimeMillis() % 4000L;
     // float angle = 0.090f * ((int) time);
     <strong>Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);</strong>
 
     // Combine the rotation matrix with the projection and camera view
-    Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
+    // Note that the mMVPMatrix factor *must be first* in order
+    // for the matrix multiplication product to be correct.
+    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
 
     // Draw triangle
-    mTriangle.draw(mMVPMatrix);
+    mTriangle.draw(scratch);
 }
 </pre>
 
diff --git a/docs/html/training/id-auth/index.jd b/docs/html/training/id-auth/index.jd
index 2bae9c4..f15ee29 100644
--- a/docs/html/training/id-auth/index.jd
+++ b/docs/html/training/id-auth/index.jd
@@ -1,5 +1,5 @@
 page.title=Remembering Users
-page.tags="privacy","oauth","accounts"
+page.tags=privacy,oauth,accounts
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/implementing-navigation/ancestral.jd b/docs/html/training/implementing-navigation/ancestral.jd
index 12d5005..57251c1 100644
--- a/docs/html/training/implementing-navigation/ancestral.jd
+++ b/docs/html/training/implementing-navigation/ancestral.jd
@@ -1,5 +1,5 @@
 page.title=Providing Up Navigation
-page.tags="up navigation","NavUtils","TaskStackBuilder"
+page.tags=up navigation,NavUtils,TaskStackBuilder
 
 trainingnavtop=true
 
diff --git a/docs/html/training/implementing-navigation/lateral.jd b/docs/html/training/implementing-navigation/lateral.jd
index bb9d78c..9c83479 100644
--- a/docs/html/training/implementing-navigation/lateral.jd
+++ b/docs/html/training/implementing-navigation/lateral.jd
@@ -1,5 +1,5 @@
 page.title=Creating Swipe Views with Tabs
-page.tags="viewpager","horizontal","paging","swipe view","tabs"
+page.tags=viewpager,horizontal,paging,swipe view,tabs
 
 trainingnavtop=true
 
diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd
index 9a94810..b9c4873 100644
--- a/docs/html/training/implementing-navigation/nav-drawer.jd
+++ b/docs/html/training/implementing-navigation/nav-drawer.jd
@@ -1,5 +1,5 @@
 page.title=Creating a Navigation Drawer
-page.tags="DrawerLayout", "navigation"
+page.tags=DrawerLayout,navigation
 
 trainingnavtop=true
 
diff --git a/docs/html/training/implementing-navigation/temporal.jd b/docs/html/training/implementing-navigation/temporal.jd
index 3abab53..e736648 100644
--- a/docs/html/training/implementing-navigation/temporal.jd
+++ b/docs/html/training/implementing-navigation/temporal.jd
@@ -1,5 +1,5 @@
 page.title=Providing Proper Back Navigation
-page.tags="back navigation","NavUtils","TaskStackBuilder"
+page.tags=back navigation,NavUtils,TaskStackBuilder
 
 trainingnavtop=true
 
diff --git a/docs/html/training/improving-layouts/index.jd b/docs/html/training/improving-layouts/index.jd
index af29d3f..2f44c30 100644
--- a/docs/html/training/improving-layouts/index.jd
+++ b/docs/html/training/improving-layouts/index.jd
@@ -1,5 +1,5 @@
 page.title=Improving Layout Performance
-page.tags="include","merge","viewstub","listview"
+page.tags=include,merge,viewstub,listview
 
 trainingnavtop=true
 startpage=true
@@ -56,4 +56,4 @@
     <dd>If you've built an instance of {@link android.widget.ListView} that contains complex or
 data-heavy content in each list item, the scroll performance of the list might suffer. This
 lesson provides some tips about how you can make your scrolling performance more smooth.</dd>
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/training/in-app-billing/index.jd b/docs/html/training/in-app-billing/index.jd
index 94708b8..4a446f3 100644
--- a/docs/html/training/in-app-billing/index.jd
+++ b/docs/html/training/in-app-billing/index.jd
@@ -1,5 +1,5 @@
 page.title=Selling In-app Products
-page.tags="billing"
+page.tags=billing
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/keyboard-input/index.jd b/docs/html/training/keyboard-input/index.jd
index 7ac79e6..46795c4 100644
--- a/docs/html/training/keyboard-input/index.jd
+++ b/docs/html/training/keyboard-input/index.jd
@@ -1,5 +1,5 @@
 page.title=Handling Keyboard Input
-page.tags="edittext","accessibility"
+page.tags=edittext,accessibility
 
 trainingnavtop=true
 startpage=true
@@ -52,4 +52,4 @@
     <dd>Learn how to respond directly to keyboard input for user actions.
     </dd>
  
-</dl> 
\ No newline at end of file
+</dl> 
diff --git a/docs/html/training/load-data-background/index.jd b/docs/html/training/load-data-background/index.jd
index 29108e8..e991003 100644
--- a/docs/html/training/load-data-background/index.jd
+++ b/docs/html/training/load-data-background/index.jd
@@ -1,5 +1,5 @@
 page.title=Loading Data in the Background
-page.tags="cursorloader"
+page.tags=cursorloader
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd
index e03eac6..249c42d 100644
--- a/docs/html/training/location/index.jd
+++ b/docs/html/training/location/index.jd
@@ -1,5 +1,5 @@
 page.title=Making Your App Location-Aware
-page.tags="location","geofence", "geofencing", "activity recognition", "activity detection", "gps"
+page.tags=location,geofence,geofencing,activity recognition,activity detection,gps
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/location/location-testing.jd b/docs/html/training/location/location-testing.jd
index e36bac1..5021fc0 100644
--- a/docs/html/training/location/location-testing.jd
+++ b/docs/html/training/location/location-testing.jd
@@ -11,7 +11,7 @@
 <ol>
     <li><a href="#TurnOnMockMode">Turn On Mock Mode</a></li>
     <li><a href="#SendMockLocations">Send Mock Locations</a></li>
-    <li><a href="RunProvider">Run the Mock Location Provider App</a></li>
+    <li><a href="#RunProvider">Run the Mock Location Provider App</a></li>
     <li><a href="#TestingTips">Testing Tips</a>
 </ol>
 
@@ -62,7 +62,7 @@
     The best way to use mock locations is to send them from a separate mock location provider app.
     This lesson includes a provider app that you can download and use to test your own software.
     Modify the provider app as necessary to suit your own needs. Some ideas for providing test data
-    to the app are listed in the section <a href="TestData">Managing test data</a>.
+    to the app are listed in the section <a href="#TestData">Managing test data</a>.
 </p>
 <p>
     The remainder of this lesson shows you how to turn on mock mode and use a location client to
diff --git a/docs/html/training/managing-audio/index.jd b/docs/html/training/managing-audio/index.jd
index 3e3bcf0..9391449 100644
--- a/docs/html/training/managing-audio/index.jd
+++ b/docs/html/training/managing-audio/index.jd
@@ -1,5 +1,5 @@
 page.title=Managing Audio Playback
-page.tags="audio","media"
+page.tags=audio,media
 
 trainingnavtop=true
 startpage=true
@@ -58,4 +58,4 @@
   <dt><b><a href="audio-output.html">Dealing with Audio Output Hardware</a></b></dt>
   <dd>Audio can be played from a number of sources. Learn how to find out where the audio is being
 played and how to handle a headset being disconnected during playback.</dd> 
- </dl> 
\ No newline at end of file
+ </dl> 
diff --git a/docs/html/training/monitoring-device-state/index.jd b/docs/html/training/monitoring-device-state/index.jd
index c3d700a..949c1da 100644
--- a/docs/html/training/monitoring-device-state/index.jd
+++ b/docs/html/training/monitoring-device-state/index.jd
@@ -1,5 +1,5 @@
 page.title=Optimizing Battery Life
-page.tags="network","internet"
+page.tags=network,internet
 
 trainingnavtop=true
 startpage=true
@@ -59,4 +59,4 @@
 those that aren't necessary due to the current device state. Learn to improve
 efficiency by toggling and cascading state change receivers and delay actions until the device is in
 a specific state.</dd>
-</dl> 
\ No newline at end of file
+</dl> 
diff --git a/docs/html/training/multiple-apks/index.jd b/docs/html/training/multiple-apks/index.jd
index 5754da9..40a26b9 100644
--- a/docs/html/training/multiple-apks/index.jd
+++ b/docs/html/training/multiple-apks/index.jd
@@ -1,5 +1,5 @@
 page.title=Maintaining Multiple APKs
-page.tags="support"
+page.tags=support
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/multiple-threads/index.jd b/docs/html/training/multiple-threads/index.jd
index cbd42b4..136f0af 100644
--- a/docs/html/training/multiple-threads/index.jd
+++ b/docs/html/training/multiple-threads/index.jd
@@ -1,5 +1,5 @@
 page.title=Sending Operations to Multiple Threads
-page.tags="threadpool","runnable"
+page.tags=threadpool,runnable
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/multiscreen/index.jd b/docs/html/training/multiscreen/index.jd
index 2d34b28..45b6161 100644
--- a/docs/html/training/multiscreen/index.jd
+++ b/docs/html/training/multiscreen/index.jd
@@ -1,5 +1,5 @@
 page.title=Designing for Multiple Screens
-page.tags="tablet","tv","fragments","support"
+page.tags=tablet,tv,fragments,support
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/notify-user/index.jd b/docs/html/training/notify-user/index.jd
index 51f058f..f7d0f87 100644
--- a/docs/html/training/notify-user/index.jd
+++ b/docs/html/training/notify-user/index.jd
@@ -1,5 +1,5 @@
 page.title=Notifying the User
-page.tags="notifications"
+page.tags=notifications
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/printing/index.jd b/docs/html/training/printing/index.jd
index 7b67b74..5b34a9d 100644
--- a/docs/html/training/printing/index.jd
+++ b/docs/html/training/printing/index.jd
@@ -1,5 +1,5 @@
 page.title=Printing Content
-page.tags="print","navigation","gesturedetector","scroller"
+page.tags=print,navigation,gesturedetector,scroller
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/run-background-service/index.jd b/docs/html/training/run-background-service/index.jd
index 3360df5..22f3fc8 100644
--- a/docs/html/training/run-background-service/index.jd
+++ b/docs/html/training/run-background-service/index.jd
@@ -1,5 +1,5 @@
 page.title=Running in a Background Service
-page.tags="intentservice"
+page.tags=intentservice
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/scheduling/index.jd b/docs/html/training/scheduling/index.jd
index 9ffbc16..4d2db60 100644
--- a/docs/html/training/scheduling/index.jd
+++ b/docs/html/training/scheduling/index.jd
@@ -1,5 +1,5 @@
 page.title=Managing Device Awake State
-page.tags=""
+page.tags=
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/search/index.jd b/docs/html/training/search/index.jd
index 4070372..612e8e8 100644
--- a/docs/html/training/search/index.jd
+++ b/docs/html/training/search/index.jd
@@ -1,5 +1,5 @@
 page.title=Adding Search Functionality
-page.tags="searchview","database"
+page.tags=searchview,database
 
 trainingnavtop=true
 startpage=true
@@ -50,4 +50,4 @@
     <dt><b><a href="backward-compat.html">Remaining Backward Compatible</a></b></dt>
 
     <dd>Learn how to keep search features backward compatible with older devices by using.</dd>
-  </dl>
\ No newline at end of file
+  </dl>
diff --git a/docs/html/training/secure-file-sharing/index.jd b/docs/html/training/secure-file-sharing/index.jd
index aa009fc..4adc1c0 100644
--- a/docs/html/training/secure-file-sharing/index.jd
+++ b/docs/html/training/secure-file-sharing/index.jd
@@ -1,5 +1,5 @@
 page.title=Sharing Files
-page.tags="FileProvider","share","ContentProvider"
+page.tags=FileProvider,share,ContentProvider
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/sharing/index.jd b/docs/html/training/sharing/index.jd
index 06d42fc..58a69fc 100644
--- a/docs/html/training/sharing/index.jd
+++ b/docs/html/training/sharing/index.jd
@@ -1,5 +1,5 @@
 page.title=Sharing Simple Data
-page.tags="intents","share"
+page.tags=intents,share
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/system-ui/dim.jd b/docs/html/training/system-ui/dim.jd
index 7c365d7..f28c948 100644
--- a/docs/html/training/system-ui/dim.jd
+++ b/docs/html/training/system-ui/dim.jd
@@ -29,6 +29,14 @@
     </li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}samples/ImmersiveMode/index.html"
+class="button">Get the sample</a>
+ <p class="filename">ImmersiveMode sample</p>
+</div>
+
 
 </div>
 </div>
diff --git a/docs/html/training/system-ui/immersive.jd b/docs/html/training/system-ui/immersive.jd
new file mode 100644
index 0000000..21672c8
--- /dev/null
+++ b/docs/html/training/system-ui/immersive.jd
@@ -0,0 +1,285 @@
+page.title=Using Immersive Full-Screen Mode
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#compare">Choose an Approach</a></li>
+  <li><a href="#nonsticky">Use IMMERSIVE</a></li>
+  <li><a href="#sticky">Use IMMERSIVE_STICKY</a></li>
+</ol>
+
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+
+<ul>
+    <li>
+        <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+    </li>
+    <li>
+        <a href="{@docRoot}design/patterns/fullscreen.html">
+        Android Design Guide
+        </a>
+    </li>
+</ul>
+
+
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}samples/ImmersiveMode/index.html"
+class="button">Get the sample</a>
+ <p class="filename">ImmersiveMode sample</p>
+</div>
+
+</div>
+</div>
+
+<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=cBi8fjv90E4">
+<div>
+    <h3>Video</h3>
+    <p>DevBytes: Android 4.4 Immersive Mode</p>
+</div>
+</a>
+
+<p>Android 4.4 (API Level 19) introduces a new
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE} flag for
+{@link android.view.View#setSystemUiVisibility setSystemUiVisibility()} that lets your app
+go truly "full screen." This flag, when combined with the
+{@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} and
+{@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} flags, hides the navigation and status
+bars and lets your app capture all touch events on the screen.</p>
+
+<p>When immersive full-screen mode is
+enabled, your activity continues to receive all touch events. The user can reveal the
+system bars with an inward swipe along the region where the system bars normally appear.
+This clears the {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} flag
+(and the {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} flag, if applied) so the
+system bars become visible. This also triggers your
+{@link android.view.View.OnSystemUiVisibilityChangeListener},
+if set. However, if you'd like the system bars to automatically hide
+again after a few moments, you can instead use the
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} flag. Note that the
+"sticky" version of the flag doesn't trigger any listeners, as system bars temporarily
+shown in this mode are in a transient state.
+</p>
+
+ <p>When you use {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} or
+ {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY},
+ the system UI stays hidden, even while users are interacting with your
+app or game. You can capture touch events from anywhere across the screen, even areas that
+would otherwise be occupied by the system bars. This gives you a great way to create a
+larger, richer, more <a href="{@docRoot}design/patterns/fullscreen.html">
+immersive</a> UI in your app or game and reduce visual distraction at the same time.</p>
+
+<p>Figure 1 illustrates the different "immersive mode" states:</p>
+
+ <img src="{@docRoot}images/training/imm-states.png"
+  alt="system bars">
+<p class="img-caption"><strong>Figure 1.</strong> Immersive mode states.</p>
+
+<p>In figure 1:</p>
+<ol>
+<li><strong>Non-immersive mode</strong>&mdash;This is how the app
+appears before it enters immersive mode. It is also how the app appears if you use the
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} flag, and the user swipes to
+display the system bars, thereby clearing the {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} and
+{@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} flags. Once these flags are cleared, the system
+bars reappear and remain visible.</li>
+
+<p>Note that it's best practice to
+ keep all UI controls in sync with the system bars, to minimize the
+ number of states your screen can be in. This provides a more seamless user experience. So
+ here all UI controls are displayed along with the status bars. Once the app enters
+ immersive mode, the UI controls are hidden along with the system bars.
+ To ensure that your UI visibility stays in sync with system bar visibility, make sure to
+ provide an appropriate {@link android.view.View.OnSystemUiVisibilityChangeListener}
+ to watch for changes, as described in
+ <a href="visibility.html">Responding to UI Visibility Changes</a>.</p></li>
+
+<li><strong>Reminder bubble</strong>&mdash;The system displays a reminder bubble
+the first time users enter
+immersive mode in your app. The reminder bubble reminds users how to display
+the system bars.
+<p class="note"><strong>Note:</strong> If you want to force the reminder bubble to appear
+for testing purposes, you can do so by putting the app in immersive mode, turning off the
+screen with the power button, and then turning the screen back on again within 5 seconds.
+</p></li>
+
+<li><strong>Immersive mode</strong>&mdash;This is the app in immersive mode, with the
+system bars and other UI controls hidden. You can achieve this state with either
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} or
+ {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY}. </li>
+
+<li><strong>Sticky flag</strong>&mdash;This is the UI you see if you use the
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag,
+and the user swipes to display the system bars. Semi-transparent bars temporarily appear and then
+hide again. The act of swiping doesn't clear any flags, nor does it trigger your
+system UI visibility change listeners, because the transient appearance of the system bars isn't
+considered a UI visibility change.</li>
+</ol>
+
+<p class="note"><strong>Note:</strong> Remember that the "immersive" flags only take effect
+if you use them in conjunction with {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION},
+{@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}, or
+ both. You can just use one or the other, but it's common to hide both the status and the
+ navigation bar when you're implementing "full immersion" mode.</p>
+
+ <h2 id="compare">Choose an Approach</h2>
+
+ <p>The flags  {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE} and
+ {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} both provide an immersive
+ experience. But whereas the
+ {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY}
+ flag causes semi-transparent system bars to briefly show and then hide again in response to
+ a swipe gesture, the same swipe gesture causes the system bars to reappear and remain
+ visible if you instead use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE}
+ flag. Here are examples of when you would use one vs. the other:</p>
+
+<ul>
+<li>If you're building a book reader, news reader, or a magazine, use
+the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} flag in conjunction
+with {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} and
+{@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Because users may want to access
+the action bar and other UI controls somewhat frequently, but not be bothered with any UI
+elements while flipping through content,
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} is a good option for this
+use case.</li>
+
+<li>If you're building a truly immersive app, where you expect users to interact near
+the edges of the screen and you don't expect them to need frequent access to the system
+UI, use the
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag
+in conjunction with {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN} and
+{@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION}. For example, this approach
+might be suitable for a game or a drawing app.</li>
+
+<li>If you're building a video player or some other app that requires minimal user
+interaction, you can probably get by with the <a href="{@docRoot}design/patterns/fullscreen.html">
+lean back</a> approach, available since
+Android 4.0 (API Level 14). For this type of app, simply using
+{@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}
+ and {@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION} should be
+sufficient. Don't use the "immersive" flags in this case.</li>
+</ul>
+
+<h2 id="nonsticky">Use IMMERSIVE</h2>
+
+ <p>When you use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE} flag, it hides
+ the system bars based on what other UI flags you have set
+ ({@link android.view.View#SYSTEM_UI_FLAG_HIDE_NAVIGATION},
+ {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}, or
+ both). When the user swipes inward in a system bars region, the
+system bars reappear and remain visible.</p>
+
+<p>It's good practice to include other system UI flags (such as
+{@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} and
+{@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE}) to keep the content from resizing
+when the system bars hide and show. You should also make sure that the action bar and other
+UI controls are hidden at the same time. This snippet demonstrates how to hide and show the
+status and navigation bars, without resizing the content:</p>
+
+<pre>
+// This snippet hides the system bars.
+private void hideSystemUI() {
+    // Set the IMMERSIVE flag.
+    // Set the content to appear under the system bars so that the content
+    // doesn't resize when the system bars hide and show.
+    mDecorView.setSystemUiVisibility(
+            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
+            | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
+            | View.SYSTEM_UI_FLAG_IMMERSIVE);
+}
+
+// This snippet shows the system bars. It does this by removing all the flags
+// except for the ones that make the content appear under the system bars.
+private void showSystemUI() {
+    mDecorView.setSystemUiVisibility(
+            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+}
+</pre>
+
+
+<p>You may also want to implement the following in conjunction with the
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} flag to provide a better user
+experience:</p>
+
+<ul>
+<li>Register a listener so that your app can get notified of system UI visibility changes,
+as described in <a href="visibility.html">Responding to UI Visibility Changes</a>.</li>
+
+<li>Implement {@link android.app.Activity#onWindowFocusChanged onWindowFocusChanged()}.
+If you gain window focus, you may want to re-hide the system bars.
+If you lose window focus, for example due to a dialog or pop up menu showing above your app,
+you'll probably want to cancel any pending "hide" operations you previously scheduled
+with {@link android.os.Handler#postDelayed Handler.postDelayed()} or something similar.</li>
+
+<li>Implement a {@link android.view.GestureDetector} that detects
+{@link android.view.GestureDetector.OnGestureListener#onSingleTapUp}, to allow users to
+manually toggle the visibility of the system bars by touching your content.
+Simple click listeners aren't the best solution for this because they get triggered even
+if the user drags a finger across the screen (assuming the click target takes up the whole
+screen).
+</li>
+
+</ul>
+
+<p>
+For more discussion of these topics, watch the video
+<a class ="external-link" href="http://www.youtube.com/embed/cBi8fjv90E4">DevBytes:
+ Android 4.4 Immersive Mode</a>.</p>
+
+<h2 id="sticky">Use IMMERSIVE_STICKY</h2>
+
+<p>When you use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY} flag,
+an inward swipe in the system bars areas causes the bars to temporarily appear in a
+semi-transparent state, but no flags are cleared, and your
+system UI visibility change listeners are not triggered. The bars
+automatically hide again after a short delay, or if the user interacts with the middle of the
+screen.</p>
+
+<p>Figure 2 shows the semi-transparent system bars that briefly appear and then hide again
+when you use the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag.</p>
+
+ <img src="{@docRoot}images/training/imm-sticky.png"
+  alt="system bars">
+<p class="img-caption"><strong>Figure 2.</strong> Auto-hiding system bars.</p>
+
+<p>Below is a simple approach to using this flag. Any time the window receives focus, simply
+set the {@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY} flag, along
+with the other flags discussed in <a href="#nonsticky">Use IMMERSIVE</a>. For example:</p>
+
+<pre>
+&#64;Override
+public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+    if (hasFocus) {
+        decorView.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> If you like the auto-hiding behavior of
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY IMMERSIVE_STICKY}
+but need to show your own UI controls as well, just use
+{@link android.view.View#SYSTEM_UI_FLAG_IMMERSIVE IMMERSIVE} combined with
+{@link android.os.Handler#postDelayed Handler.postDelayed()} or something similar to
+re-enter immersive mode after a few seconds.</p>
diff --git a/docs/html/training/system-ui/index.jd b/docs/html/training/system-ui/index.jd
index 7135a3d..56fa54b 100644
--- a/docs/html/training/system-ui/index.jd
+++ b/docs/html/training/system-ui/index.jd
@@ -1,5 +1,5 @@
 page.title=Managing the System UI
-page.tags=""
+page.tags=
 
 trainingnavtop=true
 startpage=true
@@ -20,7 +20,27 @@
   <li>Android 1.6 (API Level 4) or higher</li>
 </ul>
 
+<h2>You should also read</h2>
 
+<ul>
+    <li>
+        <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> API Guide
+    </li>
+    <li>
+        <a href="{@docRoot}design/patterns/fullscreen.html">
+        Android Design Guide
+        </a>
+    </li>
+
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}samples/ImmersiveMode/index.html"
+class="button">Get the sample</a>
+ <p class="filename">ImmersiveMode sample</p>
+</div>
 
 </div>
 </div>
@@ -32,6 +52,13 @@
 </div>
 </a>
 
+<a class="notice-developers-video wide" href="http://www.youtube.com/watch?v=cBi8fjv90E4">
+<div>
+    <h3>Video</h3>
+    <p>DevBytes: Android 4.4 Immersive Mode</p>
+</div>
+</a>
+
 <div class="figure" style="width:278px">
   <img src="{@docRoot}images/training/system-ui.png"
   alt="system bars" />
@@ -78,6 +105,12 @@
     <dd>
         Learn how to hide the navigation bar, in addition to the status bar.
     </dd>
+     <dt>
+        <strong><a href="immersive.html">Using Immersive Full-Screen Mode</a></strong>
+    </dt>
+    <dd>
+        Learn how to create a fully immersive experience in your app.
+    </dd>
 
     <dt>
         <strong><a href="visibility.html">Responding to UI Visibility Changes</a></strong>
@@ -87,4 +120,4 @@
         so that you can adjust your app's UI accordingly.
     </dd>
 
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/training/system-ui/navigation.jd b/docs/html/training/system-ui/navigation.jd
index 3843da3..3907bb2 100644
--- a/docs/html/training/system-ui/navigation.jd
+++ b/docs/html/training/system-ui/navigation.jd
@@ -10,7 +10,7 @@
 <!-- table of contents -->
 <h2>This lesson teaches you to</h2>
 <ol>
-  <li><a href="#40">Hiding the Navigation Bar on 4.0 and Higher</a></li>
+  <li><a href="#40">Hide the Navigation Bar on 4.0 and Higher</a></li>
   <li><a href="#behind">Make Content Appear Behind the Navigation Bar</a></li>
 </ol>
 
@@ -29,6 +29,13 @@
     </li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}samples/ImmersiveMode/index.html"
+class="button">Get the sample</a>
+ <p class="filename">ImmersiveMode sample</p>
+</div>
 
 </div>
 </div>
@@ -90,7 +97,7 @@
 <p>On Android 4.1 and higher, you can set your application's content to appear behind
 the navigation bar, so that the content doesn't resize as the navigation bar hides and
 shows. To do this, use
-{@link android.view.View#setSystemUiVisibility setSystemuiVisibility(SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)}.
+{@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
 You may also need to use
 {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} to help your app maintain a
 stable layout.</p>
diff --git a/docs/html/training/system-ui/status.jd b/docs/html/training/system-ui/status.jd
index 25ee253..06b6143 100644
--- a/docs/html/training/system-ui/status.jd
+++ b/docs/html/training/system-ui/status.jd
@@ -12,6 +12,7 @@
 <ol>
   <li><a href="#40">Hide the Status Bar on Android 4.0 and Lower</a></li>
   <li><a href="#41">Hide the Status Bar on Android 4.1 and Higher</a></li>
+  <li><a href="#44">Hide the Status Bar on Android 4.4 and Higher</a></li>
 
   <li><a href="#behind">Make Content Appear Behind the Status Bar</a></li>
   <li><a href="#action-bar">Synchronize the Status Bar with Action Bar Transition</a></li>
@@ -31,6 +32,13 @@
     </li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}samples/ImmersiveMode/index.html"
+class="button">Get the sample</a>
+ <p class="filename">ImmersiveMode sample</p>
+</div>
 
 </div>
 </div>
@@ -160,15 +168,13 @@
   set with {@link android.view.View#setSystemUiVisibility setSystemUiVisibility()}
   to be cleared.</li>
 </ul>
-
-
  </p>
 
  <h2 id="behind">Make Content Appear Behind the Status Bar</h2>
 <p>On Android 4.1 and higher, you can set your application's content to appear behind
 the status bar, so that the content doesn't resize as the status bar hides and shows.
 To do this, use
-{@link android.view.View#setSystemUiVisibility setSystemuiVisibility(SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)}.
+{@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
 You may also need to use
 {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} to help your app maintain a
 stable layout.</p>
@@ -209,12 +215,12 @@
 
 
 <p>Then use
-{@link android.view.View#setSystemUiVisibility setSystemuiVisibility(SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)},
+{@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN},
 as described above,
 to set  your activity layout to use the same screen area that's available when you've enabled
 {@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}.
 
-When you want to hide the system UI, call
-{@link android.view.View#setSystemUiVisibility setSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN)}.
+When you want to hide the system UI, use
+{@link android.view.View#SYSTEM_UI_FLAG_FULLSCREEN}.
 This also hides the action bar (because {@code windowActionBarOverlay=”true”)} and does
 so with a coordinated animation when both hiding and showing the two.</p>
diff --git a/docs/html/training/system-ui/visibility.jd b/docs/html/training/system-ui/visibility.jd
index c26092c..b562add 100644
--- a/docs/html/training/system-ui/visibility.jd
+++ b/docs/html/training/system-ui/visibility.jd
@@ -28,6 +28,13 @@
     </li>
 </ul>
 
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}samples/ImmersiveMode/index.html"
+class="button">Get the sample</a>
+ <p class="filename">ImmersiveMode sample</p>
+</div>
 
 </div>
 </div>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 547faae..1314c7a 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -990,6 +990,10 @@
             Hiding the Navigation Bar
           </a>
           </li>
+          <li><a href="/training/system-ui/immersive.html">
+            Using Immersive Full-Screen Mode
+          </a>
+          </li>
           <li><a href="<?cs var:toroot ?>training/system-ui/visibility.html">
             Responding to UI Visibility Changes
           </a>
diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd
index 9d15f46..7c4abc7 100644
--- a/docs/html/training/tv/index.jd
+++ b/docs/html/training/tv/index.jd
@@ -1,5 +1,5 @@
 page.title=Designing for TV
-page.tags="input","screens"
+page.tags=input,screens
 
 trainingnavtop=true
 startpage=true
@@ -48,4 +48,4 @@
   <dt><b><a href="unsupported-features-tv.html">Handling features not supported on TV</a></b></dt>
     <dd>Lists the hardware features that are usually not available on TVs. This lesson also shows you how to 
     provide alternatives for missing features or check for missing features and disable code at run time.</dd>
-</dl> 
\ No newline at end of file
+</dl> 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 6d60dd2..3c24683 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1167,6 +1167,11 @@
      * @see #reconfigure(int, int, Config)
      */
     public final int getAllocationByteCount() {
+        if (mBuffer == null) {
+            // native backed bitmaps don't support reconfiguration,
+            // so alloc size is always content size
+            return getByteCount();
+        }
         return mBuffer.length;
     }
 
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index b73db74..b714fab 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -259,14 +259,26 @@
          * (e.g. the bitmap is drawn, getPixels() is called), they will be
          * automatically re-decoded.
          *
-         * For the re-decode to happen, the bitmap must have access to the
+         * <p>For the re-decode to happen, the bitmap must have access to the
          * encoded data, either by sharing a reference to the input
          * or by making a copy of it. This distinction is controlled by
          * inInputShareable. If this is true, then the bitmap may keep a shallow
          * reference to the input. If this is false, then the bitmap will
          * explicitly make a copy of the input data, and keep that. Even if
          * sharing is allowed, the implementation may still decide to make a
-         * deep copy of the input data.
+         * deep copy of the input data.</p>
+         *
+         * <p>While inPurgeable can help avoid big Dalvik heap allocations (from
+         * API level 11 onward), it sacrifices performance predictability since any
+         * image that the view system tries to draw may incur a decode delay which
+         * can lead to dropped frames. Therefore, most apps should avoid using
+         * inPurgeable to allow for a fast and fluid UI. To minimize Dalvik heap
+         * allocations use the {@link #inBitmap} flag instead.</p>
+         *
+         * <p class="note"><strong>Note:</strong> This flag is ignored when used
+         * with {@link #decodeResource(Resources, int,
+         * android.graphics.BitmapFactory.Options)} or {@link #decodeFile(String,
+         * android.graphics.BitmapFactory.Options)}.</p>
          */
         public boolean inPurgeable;
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d46238f..13f4299 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1403,7 +1403,7 @@
             throw new IndexOutOfBoundsException();
         }
         native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+                paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1417,7 +1417,7 @@
      */
     public void drawText(String text, float x, float y, Paint paint) {
         native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+                paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1436,7 +1436,7 @@
             throw new IndexOutOfBoundsException();
         }
         native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
-                paint.mNativePaint);
+                paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1456,7 +1456,7 @@
         if (text instanceof String || text instanceof SpannedString ||
             text instanceof SpannableString) {
             native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawText(this, start, end, x, y,
                     paint);
@@ -1464,7 +1464,7 @@
             char[] buf = TemporaryBuffer.obtain(end - start);
             TextUtils.getChars(text, start, end, buf, 0);
             native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
-                    paint.mBidiFlags, paint.mNativePaint);
+                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1507,7 +1507,7 @@
         }
 
         native_drawTextRun(mNativeCanvas, text, index, count,
-                contextIndex, contextCount, x, y, dir, paint.mNativePaint);
+                contextIndex, contextCount, x, y, dir, paint.mNativePaint, paint.mNativeTypeface);
     }
 
     /**
@@ -1545,7 +1545,7 @@
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             native_drawTextRun(mNativeCanvas, text.toString(), start, end,
-                    contextStart, contextEnd, x, y, flags, paint.mNativePaint);
+                    contextStart, contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
         } else if (text instanceof GraphicsOperations) {
             ((GraphicsOperations) text).drawTextRun(this, start, end,
                     contextStart, contextEnd, x, y, flags, paint);
@@ -1555,7 +1555,7 @@
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
-                    0, contextLen, x, y, flags, paint.mNativePaint);
+                    0, contextLen, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -1814,18 +1814,18 @@
     
     private static native void native_drawText(int nativeCanvas, char[] text,
                                                int index, int count, float x,
-                                               float y, int flags, int paint);
+                                               float y, int flags, int paint, int typeface);
     private static native void native_drawText(int nativeCanvas, String text,
                                                int start, int end, float x,
-                                               float y, int flags, int paint);
+                                               float y, int flags, int paint, int typeface);
 
     private static native void native_drawTextRun(int nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
-            float x, float y, int flags, int paint);
+            float x, float y, int flags, int paint, int typeface);
 
     private static native void native_drawTextRun(int nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
-            float x, float y, int flags, int paint);
+            float x, float y, int flags, int paint, int typeface);
 
     private static native void native_drawPosText(int nativeCanvas,
                                                   char[] text, int index,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 5fc2588..c2d4df2 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -33,6 +33,10 @@
      * @hide
      */
     public int mNativePaint;
+    /**
+     * @hide
+     */
+    public int mNativeTypeface;
 
     private ColorFilter mColorFilter;
     private MaskFilter  mMaskFilter;
@@ -481,6 +485,7 @@
         mRasterizer = null;
         mShader = null;
         mTypeface = null;
+        mNativeTypeface = 0;
         mXfermode = null;
 
         mHasCompatScaling = false;
@@ -525,6 +530,7 @@
             mShader = null;
         }
         mTypeface = paint.mTypeface;
+        mNativeTypeface = paint.mNativeTypeface;
         mXfermode = paint.mXfermode;
 
         mHasCompatScaling = paint.mHasCompatScaling;
@@ -1087,6 +1093,7 @@
         }
         native_setTypeface(mNativePaint, typefaceNative);
         mTypeface = typeface;
+        mNativeTypeface = typefaceNative;
         return typeface;
     }
     
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 5b04a91..09481d4 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -16,8 +16,6 @@
 
 package android.graphics;
 
-import android.view.HardwareRenderer;
-
 /**
  * The Path class encapsulates compound (multiple contour) geometric paths
  * consisting of straight line segments, quadratic curves, and cubic curves.
@@ -39,7 +37,6 @@
      * @hide
      */
     public Region rects;
-    private boolean mDetectSimplePaths;
     private Direction mLastDirection = null;
 
     /**
@@ -47,7 +44,6 @@
      */
     public Path() {
         mNativePath = init1();
-        mDetectSimplePaths = HardwareRenderer.isAvailable();
     }
 
     /**
@@ -65,7 +61,6 @@
             }
         }
         mNativePath = init2(valNative);
-        mDetectSimplePaths = HardwareRenderer.isAvailable();
     }
     
     /**
@@ -74,10 +69,8 @@
      */
     public void reset() {
         isSimplePath = true;
-        if (mDetectSimplePaths) {
-            mLastDirection = null;
-            if (rects != null) rects.setEmpty();
-        }
+        mLastDirection = null;
+        if (rects != null) rects.setEmpty();
         // We promised not to change this, so preserve it around the native
         // call, which does now reset fill type.
         final FillType fillType = getFillType();
@@ -91,10 +84,8 @@
      */
     public void rewind() {
         isSimplePath = true;
-        if (mDetectSimplePaths) {
-            mLastDirection = null;
-            if (rects != null) rects.setEmpty();
-        }
+        mLastDirection = null;
+        if (rects != null) rects.setEmpty();
         native_rewind(mNativePath);
     }
 
@@ -475,16 +466,14 @@
     }
     
     private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) {
-        if (mDetectSimplePaths) {
-            if (mLastDirection == null) {
-                mLastDirection = dir;
-            }
-            if (mLastDirection != dir) {
-                isSimplePath = false;
-            } else {
-                if (rects == null) rects = new Region();
-                rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION);
-            }
+        if (mLastDirection == null) {
+            mLastDirection = dir;
+        }
+        if (mLastDirection != dir) {
+            isSimplePath = false;
+        } else {
+            if (rects == null) rects = new Region();
+            rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION);
         }
     }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index c68c9f7..aea3ee5 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -48,7 +48,10 @@
     private static final SparseArray<SparseArray<Typeface>> sTypefaceCache =
             new SparseArray<SparseArray<Typeface>>(3);
 
-    int native_instance;
+    /**
+     * @hide
+     */
+    public int native_instance;
 
     // Style
     public static final int NORMAL = 0;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index e350e8d..aac7876 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -23,6 +23,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.SystemClock;
+import android.util.LayoutDirection;
 import android.util.SparseArray;
 
 /**
@@ -59,6 +60,8 @@
     private long mExitAnimationEnd;
     private Drawable mLastDrawable;
 
+    private Insets mInsets = Insets.NONE;
+
     // overrides from Drawable
 
     @Override
@@ -78,18 +81,31 @@
                 | mDrawableContainerState.mChildrenChangingConfigurations;
     }
 
+    private boolean needsMirroring() {
+        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
+    }
+
     @Override
     public boolean getPadding(Rect padding) {
         final Rect r = mDrawableContainerState.getConstantPadding();
+        boolean result;
         if (r != null) {
             padding.set(r);
-            return true;
-        }
-        if (mCurrDrawable != null) {
-            return mCurrDrawable.getPadding(padding);
+            result = (r.left | r.top | r.bottom | r.right) != 0;
         } else {
-            return super.getPadding(padding);
+            if (mCurrDrawable != null) {
+                result = mCurrDrawable.getPadding(padding);
+            } else {
+                result = super.getPadding(padding);
+            }
         }
+        if (needsMirroring()) {
+            final int left = padding.left;
+            final int right = padding.right;
+            padding.left = right;
+            padding.right = left;
+        }
+        return result;
     }
 
     /**
@@ -97,7 +113,7 @@
      */
     @Override
     public Insets getOpticalInsets() {
-        return (mCurrDrawable == null) ? Insets.NONE : mCurrDrawable.getOpticalInsets();
+        return mInsets;
     }
 
     @Override
@@ -334,6 +350,7 @@
             mCurrDrawable = d;
             mCurIndex = idx;
             if (d != null) {
+                mInsets = d.getOpticalInsets();
                 d.mutate();
                 if (mDrawableContainerState.mEnterFadeDuration > 0) {
                     mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
@@ -348,9 +365,12 @@
                 d.setBounds(getBounds());
                 d.setLayoutDirection(getLayoutDirection());
                 d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
+            } else {
+                mInsets = Insets.NONE;
             }
         } else {
             mCurrDrawable = null;
+            mInsets = Insets.NONE;
             mCurIndex = -1;
         }
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 27618a5..ba4698c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -234,6 +234,23 @@
     }
 
     /**
+     * <p>Set the stroke width and color state list for the drawable. If width
+     * is zero, then no stroke is drawn.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width in pixels of the stroke
+     * @param colorStateList The color state list of the stroke
+     *
+     * @see #mutate()
+     * @see #setStroke(int, ColorStateList, float, float)
+     */
+    public void setStroke(int width, ColorStateList colorStateList) {
+        setStroke(width, colorStateList, 0, 0);
+    }
+
+    /**
      * <p>Set the stroke width and color for the drawable. If width is zero,
      * then no stroke is drawn. This method can also be used to dash the stroke.</p>
      * <p><strong>Note</strong>: changing this property will affect all instances
@@ -250,7 +267,35 @@
      */
     public void setStroke(int width, int color, float dashWidth, float dashGap) {
         mGradientState.setStroke(width, color, dashWidth, dashGap);
+        setStrokeInternal(width, color, dashWidth, dashGap);
+    }
 
+    /**
+     * <p>Set the stroke width and color state list for the drawable. If width
+     * is zero, then no stroke is drawn. This method can also be used to dash
+     * the stroke.</p>
+     * <p><strong>Note</strong>: changing this property will affect all instances
+     * of a drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing this property.</p>
+     *
+     * @param width The width in pixels of the stroke
+     * @param colorStateList The color state list of the stroke
+     * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes
+     * @param dashGap The gap in pixels between dashes
+     *
+     * @see #mutate()
+     * @see #setStroke(int, ColorStateList)
+     */
+    public void setStroke(
+            int width, ColorStateList colorStateList, float dashWidth, float dashGap) {
+        mGradientState.setStroke(width, colorStateList, dashWidth, dashGap);
+
+        final int[] stateSet = getState();
+        final int color = colorStateList.getColorForState(stateSet, 0);
+        setStrokeInternal(width, color, dashWidth, dashGap);
+    }
+
+    private void setStrokeInternal(int width, int color, float dashWidth, float dashGap) {
         if (mStrokePaint == null)  {
             mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
             mStrokePaint.setStyle(Paint.Style.STROKE);
@@ -647,24 +692,47 @@
     }
 
     @Override
-    public boolean setState(int[] stateSet) {
-        final ColorStateList stateList = mGradientState.mColorStateList;
+    public boolean onStateChange(int[] stateSet) {
+        boolean invalidateSelf = false;
+
+        final GradientState s = mGradientState;
+        final ColorStateList stateList = s.mColorStateList;
         if (stateList != null) {
             final int newColor = stateList.getColorForState(stateSet, 0);
             final int oldColor = mFillPaint.getColor();
             if (oldColor != newColor) {
                 mFillPaint.setColor(newColor);
-                invalidateSelf();
-                return true;
+                invalidateSelf = true;
             }
         }
 
-        return super.setState(stateSet);
+        final Paint strokePaint = mStrokePaint;
+        if (strokePaint != null) {
+            final ColorStateList strokeStateList = s.mStrokeColorStateList;
+            if (strokeStateList != null) {
+                final int newStrokeColor = strokeStateList.getColorForState(stateSet, 0);
+                final int oldStrokeColor = strokePaint.getColor();
+                if (oldStrokeColor != newStrokeColor) {
+                    strokePaint.setColor(newStrokeColor);
+                    invalidateSelf = true;
+                }
+            }
+        }
+
+        if (invalidateSelf) {
+            invalidateSelf();
+            return true;
+        }
+
+        return false;
     }
 
     @Override
     public boolean isStateful() {
-        return super.isStateful() || mGradientState.mColorStateList != null;
+        final GradientState s = mGradientState;
+        return super.isStateful()
+                || (s.mColorStateList != null && s.mColorStateList.isStateful())
+                || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful());
     }
 
     @Override
@@ -1015,18 +1083,18 @@
             } else if (name.equals("stroke")) {
                 a = r.obtainAttributes(attrs,
                         com.android.internal.R.styleable.GradientDrawableStroke);
-                int width = a.getDimensionPixelSize(
+                final int width = a.getDimensionPixelSize(
                         com.android.internal.R.styleable.GradientDrawableStroke_width, 0);
-                int color = a.getColor(
-                        com.android.internal.R.styleable.GradientDrawableStroke_color, 0);
-                float dashWidth = a.getDimension(
+                final ColorStateList colorStateList = a.getColorStateList(
+                        com.android.internal.R.styleable.GradientDrawableStroke_color);
+                final float dashWidth = a.getDimension(
                         com.android.internal.R.styleable.GradientDrawableStroke_dashWidth, 0);
                 if (dashWidth != 0.0f) {
-                    float dashGap = a.getDimension(
+                    final float dashGap = a.getDimension(
                             com.android.internal.R.styleable.GradientDrawableStroke_dashGap, 0);
-                    setStroke(width, color, dashWidth, dashGap);
+                    setStroke(width, colorStateList, dashWidth, dashGap);
                 } else {
-                    setStroke(width, color);
+                    setStroke(width, colorStateList);
                 }
                 a.recycle();
             } else if (name.equals("corners")) {
@@ -1119,6 +1187,7 @@
         public int mGradient = LINEAR_GRADIENT;
         public Orientation mOrientation;
         public ColorStateList mColorStateList;
+        public ColorStateList mStrokeColorStateList;
         public int[] mColors;
         public int[] mTempColors; // no need to copy
         public float[] mTempPositions; // no need to copy
@@ -1251,12 +1320,19 @@
                 return;
             }
 
-            if (mStrokeWidth > 0 && !isOpaque(mStrokeColor)) {
-                mOpaque = false;
-                return;
+            if (mStrokeWidth > 0) {
+                if (mStrokeColorStateList != null) {
+                    if (!mStrokeColorStateList.isOpaque()) {
+                        mOpaque = false;
+                        return;
+                    }
+                } else if (!isOpaque(mStrokeColor)) {
+                    mOpaque = false;
+                    return;
+                }
             }
 
-            if (mColorStateList != null && !isOpaque(mColorStateList)) {
+            if (mColorStateList != null && !mColorStateList.isOpaque()) {
                 mOpaque = false;
                 return;
             }
@@ -1282,25 +1358,26 @@
             return ((color >> 24) & 0xff) == 0xff;
         }
 
-        private static boolean isOpaque(ColorStateList colors) {
-            final int n = colors.getCount();
-            for (int i = 0; i < n; i++) {
-                if (!isOpaque(colors.getColorAt(i))) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
         public void setStroke(int width, int color) {
             mStrokeWidth = width;
             mStrokeColor = color;
+            mStrokeColorStateList = null;
             computeOpacity();
         }
 
         public void setStroke(int width, int color, float dashWidth, float dashGap) {
             mStrokeWidth = width;
             mStrokeColor = color;
+            mStrokeColorStateList = null;
+            mStrokeDashWidth = dashWidth;
+            mStrokeDashGap = dashGap;
+            computeOpacity();
+        }
+
+        public void setStroke(
+                int width, ColorStateList colorStateList, float dashWidth, float dashGap) {
+            mStrokeWidth = width;
+            mStrokeColorStateList = colorStateList;
             mStrokeDashWidth = dashWidth;
             mStrokeDashGap = dashGap;
             computeOpacity();
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/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
index 81e523d..29d14a2 100644
--- a/graphics/java/android/graphics/pdf/PdfDocument.java
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Rect;
 
 import dalvik.system.CloseGuard;
@@ -69,6 +70,12 @@
  */
 public class PdfDocument {
 
+    // TODO: We need a constructor that will take an OutputStream to
+    // support online data serialization as opposed to the current
+    // on demand one. The current approach is fine until Skia starts
+    // to support online PDF generation at which point we need to
+    // handle this.
+
     private final byte[] mChunk = new byte[4096];
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -111,7 +118,7 @@
         if (pageInfo == null) {
             throw new IllegalArgumentException("page cannot be null");
         }
-        Canvas canvas = new PdfCanvas(nativeCreatePage(pageInfo.mPageWidth,
+        Canvas canvas = new PdfCanvas(nativeStartPage(mNativeDocument, pageInfo.mPageWidth,
                 pageInfo.mPageHeight, pageInfo.mContentRect.left, pageInfo.mContentRect.top,
                 pageInfo.mContentRect.right, pageInfo.mContentRect.bottom));
         mCurrentPage = new Page(canvas, pageInfo);
@@ -142,7 +149,7 @@
         }
         mPages.add(page.getInfo());
         mCurrentPage = null;
-        nativeAppendPage(mNativeDocument, page.mCanvas.mNativeCanvas);
+        nativeFinishPage(mNativeDocument);
         page.finish();
     }
 
@@ -204,7 +211,7 @@
 
     private void dispose() {
         if (mNativeDocument != 0) {
-            nativeFinalize(mNativeDocument);
+            nativeClose(mNativeDocument);
             mCloseGuard.close();
             mNativeDocument = 0;
         }
@@ -230,14 +237,14 @@
 
     private native int nativeCreateDocument();
 
-    private native void nativeFinalize(int document);
+    private native void nativeClose(int document);
 
-    private native void nativeAppendPage(int document, int page);
+    private native void nativeFinishPage(int document);
 
     private native void nativeWriteTo(int document, OutputStream out, byte[] chunk);
 
-    private static native int nativeCreatePage(int pageWidth, int pageHeight, int contentLeft,
-            int contentTop, int contentRight, int contentBottom);
+    private static native int nativeStartPage(int documentPtr, int pageWidth, int pageHeight,
+            int contentLeft, int contentTop, int contentRight, int contentBottom);
 
     private final class PdfCanvas extends Canvas {
 
@@ -392,28 +399,28 @@
          * Gets the {@link Canvas} of the page.
          *
          * <p>
-         * <strong>Note: </strong> There are some draw operations that are
-         * not yet supported by the canvas returned by this method. More
-         * specifically:
+         * <strong>Note: </strong> There are some draw operations that are not yet
+         * supported by the canvas returned by this method. More specifically:
          * <ul>
-         * <li>{@link Canvas#clipPath(android.graphics.Path)
-         *     Canvas.clipPath(android.graphics.Path)}</li>
-         * <li>All flavors of {@link Canvas#drawText(String, float, float,
-         *     android.graphics.Paint) Canvas.drawText(String, float, float,
-         *     android.graphics.Paint)}</li>
-         * <li>All flavors of {@link Canvas#drawPosText(String, float[],
-         *     android.graphics.Paint) Canvas.drawPosText(String, float[],
-         *     android.graphics.Paint)}</li>
+         * <li>Inverse path clipping performed via {@link Canvas#clipPath(android.graphics.Path,
+         *     android.graphics.Region.Op) Canvas.clipPath(android.graphics.Path,
+         *     android.graphics.Region.Op)} for {@link
+         *     android.graphics.Region.Op#REVERSE_DIFFERENCE
+         *     Region.Op#REVERSE_DIFFERENCE} operations.</li>
          * <li>{@link Canvas#drawVertices(android.graphics.Canvas.VertexMode, int,
          *     float[], int, float[], int, int[], int, short[], int, int,
          *     android.graphics.Paint) Canvas.drawVertices(
          *     android.graphics.Canvas.VertexMode, int, float[], int, float[],
          *     int, int[], int, short[], int, int, android.graphics.Paint)}</li>
-         * <li>{@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
+         * <li>Color filters set via {@link Paint#setColorFilter(
+         *     android.graphics.ColorFilter)}</li>
+         * <li>Mask filters set via {@link Paint#setMaskFilter(
+         *     android.graphics.MaskFilter)}</li>
+         * <li>Some XFER modes such as
+         *     {@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
          *     {@link android.graphics.PorterDuff.Mode#DST_ATOP PorterDuff.DST_ATOP},
          *     {@link android.graphics.PorterDuff.Mode#XOR PorterDuff.XOR},
          *     {@link android.graphics.PorterDuff.Mode#ADD PorterDuff.ADD}</li>
-         * <li>Perspective transforms</li>
          * </ul>
          *
          * @return The canvas if the page is not finished, null otherwise.
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index bb1e743..8e69f56 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -801,7 +801,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize, Element.DataType.SIGNED_32);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -817,7 +817,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length * 2, dataSize);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize, Element.DataType.SIGNED_16);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -833,7 +833,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length, dataSize);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize, Element.DataType.SIGNED_8);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -849,7 +849,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copy1DRangeFromUnchecked");
         int dataSize = mType.mElement.getBytesSize() * count;
         data1DChecks(off, count, d.length * 4, dataSize);
-        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
+        mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize, Element.DataType.FLOAT_32);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -955,7 +955,7 @@
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length);
+                              w, h, data, data.length, Element.DataType.SIGNED_8);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -964,7 +964,7 @@
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length * 2);
+                              w, h, data, data.length * 2, Element.DataType.SIGNED_16);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -973,7 +973,7 @@
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length * 4);
+                              w, h, data, data.length * 4, Element.DataType.SIGNED_32);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -982,7 +982,7 @@
         mRS.validate();
         validate2DRange(xoff, yoff, w, h);
         mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
-                              w, h, data, data.length * 4);
+                              w, h, data, data.length * 4, Element.DataType.FLOAT_32);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1128,7 +1128,7 @@
         mRS.validate();
         validate3DRange(xoff, yoff, zoff, w, h, d);
         mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                              w, h, d, data, data.length);
+                              w, h, d, data, data.length, Element.DataType.SIGNED_8);
     }
 
     /**
@@ -1139,7 +1139,7 @@
         mRS.validate();
         validate3DRange(xoff, yoff, zoff, w, h, d);
         mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                              w, h, d, data, data.length * 2);
+                              w, h, d, data, data.length * 2, Element.DataType.SIGNED_16);
     }
 
     /**
@@ -1150,7 +1150,7 @@
         mRS.validate();
         validate3DRange(xoff, yoff, zoff, w, h, d);
         mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                              w, h, d, data, data.length * 4);
+                              w, h, d, data, data.length * 4, Element.DataType.SIGNED_32);
     }
 
     /**
@@ -1161,7 +1161,7 @@
         mRS.validate();
         validate3DRange(xoff, yoff, zoff, w, h, d);
         mRS.nAllocationData3D(getIDSafe(), xoff, yoff, zoff, mSelectedLOD,
-                              w, h, d, data, data.length * 4);
+                              w, h, d, data, data.length * 4, Element.DataType.FLOAT_32);
     }
 
 
@@ -1262,7 +1262,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsInt8();
         mRS.validate();
-        mRS.nAllocationRead(getID(mRS), d);
+        mRS.nAllocationRead(getID(mRS), d, Element.DataType.SIGNED_8);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1277,7 +1277,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsInt16();
         mRS.validate();
-        mRS.nAllocationRead(getID(mRS), d);
+        mRS.nAllocationRead(getID(mRS), d, Element.DataType.SIGNED_16);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1292,7 +1292,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsInt32();
         mRS.validate();
-        mRS.nAllocationRead(getID(mRS), d);
+        mRS.nAllocationRead(getID(mRS), d, Element.DataType.SIGNED_32);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
@@ -1307,7 +1307,7 @@
         Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
         validateIsFloat32();
         mRS.validate();
-        mRS.nAllocationRead(getID(mRS), d);
+        mRS.nAllocationRead(getID(mRS), d, Element.DataType.FLOAT_32);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
 
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 7d4a5c4..322a045 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -386,25 +386,10 @@
     }
 
 
-    native void rsnAllocationData1D(int con, int id, int off, int mip, int count, int[] d, int sizeBytes);
-    synchronized void nAllocationData1D(int id, int off, int mip, int count, int[] d, int sizeBytes) {
+    native void rsnAllocationData1D(int con, int id, int off, int mip, int count, Object d, int sizeBytes, int dt);
+    synchronized void nAllocationData1D(int id, int off, int mip, int count, Object d, int sizeBytes, Element.DataType dt) {
         validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
-    }
-    native void rsnAllocationData1D(int con, int id, int off, int mip, int count, short[] d, int sizeBytes);
-    synchronized void nAllocationData1D(int id, int off, int mip, int count, short[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
-    }
-    native void rsnAllocationData1D(int con, int id, int off, int mip, int count, byte[] d, int sizeBytes);
-    synchronized void nAllocationData1D(int id, int off, int mip, int count, byte[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
-    }
-    native void rsnAllocationData1D(int con, int id, int off, int mip, int count, float[] d, int sizeBytes);
-    synchronized void nAllocationData1D(int id, int off, int mip, int count, float[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes);
+        rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
     }
 
     native void rsnAllocationElementData1D(int con, int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes);
@@ -433,26 +418,14 @@
                             srcMip, srcFace);
     }
 
-    native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes);
-    synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes) {
+    native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face,
+                                    int w, int h, Object d, int sizeBytes, int dt);
+    synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face,
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt) {
         validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
+        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
     }
-    native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes);
-    synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
-    }
-    native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes);
-    synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
-    }
-    native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes);
-    synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes);
-    }
+
     native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, Bitmap b);
     synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, Bitmap b) {
         validate();
@@ -477,48 +450,36 @@
                             srcAlloc, srcXoff, srcYoff, srcZoff, srcMip);
     }
 
-    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, byte[] d, int sizeBytes);
-    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, byte[] d, int sizeBytes) {
+    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip,
+                                    int w, int h, int depth, Object d, int sizeBytes, int dt);
+    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip,
+                                        int w, int h, int depth, Object d, int sizeBytes, Element.DataType dt) {
         validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
-    }
-    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, short[] d, int sizeBytes);
-    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, short[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
-    }
-    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, int[] d, int sizeBytes);
-    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, int[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
-    }
-    native void rsnAllocationData3D(int con, int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, float[] d, int sizeBytes);
-    synchronized void nAllocationData3D(int id, int xoff, int yoff, int zoff, int mip, int w, int h, int depth, float[] d, int sizeBytes) {
-        validate();
-        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes);
+        rsnAllocationData3D(mContext, id, xoff, yoff, zoff, mip, w, h, depth, d, sizeBytes, dt.mID);
     }
 
+    native void rsnAllocationRead(int con, int id, Object d, int dt);
+    synchronized void nAllocationRead(int id, Object d, Element.DataType dt) {
+        validate();
+        rsnAllocationRead(mContext, id, d, dt.mID);
+    }
 
-    native void rsnAllocationRead(int con, int id, byte[] d);
-    synchronized void nAllocationRead(int id, byte[] d) {
+    native void rsnAllocationRead1D(int con, int id, int off, int mip, int count, Object d,
+                                    int sizeBytes, int dt);
+    synchronized void nAllocationRead1D(int id, int off, int mip, int count, Object d,
+                                        int sizeBytes, Element.DataType dt) {
         validate();
-        rsnAllocationRead(mContext, id, d);
+        rsnAllocationRead1D(mContext, id, off, mip, count, d, sizeBytes, dt.mID);
     }
-    native void rsnAllocationRead(int con, int id, short[] d);
-    synchronized void nAllocationRead(int id, short[] d) {
+
+    native void rsnAllocationRead2D(int con, int id, int xoff, int yoff, int mip, int face,
+                                    int w, int h, Object d, int sizeBytes, int dt);
+    synchronized void nAllocationRead2D(int id, int xoff, int yoff, int mip, int face,
+                                        int w, int h, Object d, int sizeBytes, Element.DataType dt) {
         validate();
-        rsnAllocationRead(mContext, id, d);
+        rsnAllocationRead2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes, dt.mID);
     }
-    native void rsnAllocationRead(int con, int id, int[] d);
-    synchronized void nAllocationRead(int id, int[] d) {
-        validate();
-        rsnAllocationRead(mContext, id, d);
-    }
-    native void rsnAllocationRead(int con, int id, float[] d);
-    synchronized void nAllocationRead(int id, float[] d) {
-        validate();
-        rsnAllocationRead(mContext, id, d);
-    }
+
     native int  rsnAllocationGetType(int con, int id);
     synchronized int nAllocationGetType(int id) {
         validate();
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index cbc4e5a..10d042c 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -50,6 +50,63 @@
 
 using namespace android;
 
+#define PER_ARRAY_TYPE(flag, fnc, ...) {                                                \
+    jint len = 0;                                                                       \
+    void *ptr = NULL;                                                                   \
+    size_t typeBytes = 0;                                                               \
+    switch(dataType) {                                                                  \
+    case RS_TYPE_FLOAT_32:                                                              \
+        len = _env->GetArrayLength((jfloatArray)data);                                  \
+        ptr = _env->GetFloatArrayElements((jfloatArray)data, flag);                     \
+        typeBytes = 4;                                                                  \
+        fnc(__VA_ARGS__);                                                               \
+        _env->ReleaseFloatArrayElements((jfloatArray)data, (jfloat *)ptr, JNI_ABORT);   \
+        return;                                                                         \
+    case RS_TYPE_FLOAT_64:                                                              \
+        len = _env->GetArrayLength((jdoubleArray)data);                                 \
+        ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag);                   \
+        typeBytes = 8;                                                                  \
+        fnc(__VA_ARGS__);                                                               \
+        _env->ReleaseDoubleArrayElements((jdoubleArray)data, (jdouble *)ptr, JNI_ABORT);\
+        return;                                                                         \
+    case RS_TYPE_SIGNED_8:                                                              \
+    case RS_TYPE_UNSIGNED_8:                                                            \
+        len = _env->GetArrayLength((jbyteArray)data);                                   \
+        ptr = _env->GetByteArrayElements((jbyteArray)data, flag);                       \
+        typeBytes = 1;                                                                  \
+        fnc(__VA_ARGS__);                                                               \
+        _env->ReleaseByteArrayElements((jbyteArray)data, (jbyte*)ptr, JNI_ABORT);       \
+        return;                                                                         \
+    case RS_TYPE_SIGNED_16:                                                             \
+    case RS_TYPE_UNSIGNED_16:                                                           \
+        len = _env->GetArrayLength((jshortArray)data);                                  \
+        ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
+        typeBytes = 2;                                                                  \
+        fnc(__VA_ARGS__);                                                               \
+        _env->ReleaseShortArrayElements((jshortArray)data, (jshort *)ptr, JNI_ABORT);   \
+        return;                                                                         \
+    case RS_TYPE_SIGNED_32:                                                             \
+    case RS_TYPE_UNSIGNED_32:                                                           \
+        len = _env->GetArrayLength((jintArray)data);                                    \
+        ptr = _env->GetIntArrayElements((jintArray)data, flag);                         \
+        typeBytes = 4;                                                                  \
+        fnc(__VA_ARGS__);                                                               \
+        _env->ReleaseIntArrayElements((jintArray)data, (jint *)ptr, JNI_ABORT);         \
+        return;                                                                         \
+    case RS_TYPE_SIGNED_64:                                                             \
+    case RS_TYPE_UNSIGNED_64:                                                           \
+        len = _env->GetArrayLength((jlongArray)data);                                   \
+        ptr = _env->GetLongArrayElements((jlongArray)data, flag);                       \
+        typeBytes = 8;                                                                  \
+        fnc(__VA_ARGS__);                                                               \
+        _env->ReleaseLongArrayElements((jlongArray)data, (jlong *)ptr, JNI_ABORT);      \
+        return;                                                                         \
+    default:                                                                            \
+        break;                                                                          \
+    }                                                                                   \
+}
+
+
 class AutoJavaStringToUTF8 {
 public:
     AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) {
@@ -605,43 +662,13 @@
 
 
 static void
-nAllocationData1D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jintArray data, int sizeBytes)
+nAllocationData1D(JNIEnv *_env, jobject _this, RsContext con, jint _alloc, jint offset, jint lod,
+                  jint count, jobject data, int sizeBytes, int dataType)
 {
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation1DData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
-    rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes);
-    _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData1D_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jshortArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation1DData_s, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
-    jshort *ptr = _env->GetShortArrayElements(data, NULL);
-    rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes);
-    _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData1D_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jbyteArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation1DData_b, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData1D_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jfloatArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation1DData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
-    jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
-    rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes);
-    _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+    RsAllocation *alloc = (RsAllocation *)_alloc;
+    LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i), dataType(%i)",
+            con, alloc, offset, count, len, sizeBytes, dataType);
+    PER_ARRAY_TYPE(NULL, rsAllocation1DData, con, alloc, offset, lod, count, ptr, sizeBytes);
 }
 
 static void
@@ -656,47 +683,14 @@
 }
 
 static void
-nAllocationData2D_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face,
-                    jint w, jint h, jshortArray data, int sizeBytes)
+nAllocationData2D(JNIEnv *_env, jobject _this, RsContext con, jint _alloc, jint xoff, jint yoff, jint lod, jint _face,
+                  jint w, jint h, jobject data, int sizeBytes, int dataType)
 {
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation2DData_s, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
-    jshort *ptr = _env->GetShortArrayElements(data, NULL);
-    rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes, 0);
-    _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData2D_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face,
-                    jint w, jint h, jbyteArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation2DData_b, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes, 0);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData2D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face,
-                    jint w, jint h, jintArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation2DData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
-    rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes, 0);
-    _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData2D_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face,
-                    jint w, jint h, jfloatArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation2DData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len);
-    jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
-    rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes, 0);
-    _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+    RsAllocation *alloc = (RsAllocation *)_alloc;
+    RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
+    LOG_API("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)",
+            con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
+    PER_ARRAY_TYPE(NULL, rsAllocation2DData, con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
 }
 
 static void
@@ -724,47 +718,13 @@
 }
 
 static void
-nAllocationData3D_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                    jint w, jint h, jint d, jshortArray data, int sizeBytes)
+nAllocationData3D(JNIEnv *_env, jobject _this, RsContext con, jint _alloc, jint xoff, jint yoff, jint zoff, jint lod,
+                    jint w, jint h, jint d, jobject data, int sizeBytes, int dataType)
 {
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation3DData_s, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
-    jshort *ptr = _env->GetShortArrayElements(data, NULL);
-    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-    _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData3D_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                    jint w, jint h, jint d, jbyteArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation3DData_b, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData3D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                    jint w, jint h, jint d, jintArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation3DData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
-    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-    _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData3D_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint zoff, jint lod,
-                    jint w, jint h, jint d, jfloatArray data, int sizeBytes)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation3DData_f, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, zoff, w, h, d, len);
-    jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
-    rsAllocation3DData(con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
-    _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
+    RsAllocation *alloc = (RsAllocation *)_alloc;
+    LOG_API("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i), h(%i), d(%i), sizeBytes(%i)",
+            con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, sizeBytes);
+    PER_ARRAY_TYPE(NULL, rsAllocation3DData, con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
 }
 
 static void
@@ -789,48 +749,34 @@
                             srcXoff, srcYoff, srcZoff, srcMip);
 }
 
+
 static void
-nAllocationRead_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jintArray data)
+nAllocationRead(JNIEnv *_env, jobject _this, RsContext con, jint _alloc, jobject data, int dataType)
 {
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
-    jsize length = _env->GetArrayLength(data);
-    rsAllocationRead(con, (RsAllocation)alloc, ptr, length * sizeof(int));
-    _env->ReleaseIntArrayElements(data, ptr, 0);
+    RsAllocation *alloc = (RsAllocation *)_alloc;
+    LOG_API("nAllocationRead, con(%p), alloc(%p)", con, (RsAllocation)alloc);
+    PER_ARRAY_TYPE(0, rsAllocationRead, con, alloc, ptr, len * typeBytes);
 }
 
 static void
-nAllocationRead_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jshortArray data)
+nAllocationRead1D(JNIEnv *_env, jobject _this, RsContext con, jint _alloc, jint offset, jint lod,
+                  jint count, jobject data, int sizeBytes, int dataType)
 {
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
-    jshort *ptr = _env->GetShortArrayElements(data, NULL);
-    jsize length = _env->GetArrayLength(data);
-    rsAllocationRead(con, (RsAllocation)alloc, ptr, length * sizeof(short));
-    _env->ReleaseShortArrayElements(data, ptr, 0);
+    RsAllocation *alloc = (RsAllocation *)_alloc;
+    LOG_API("nAllocation1DRead, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i), dataType(%i)",
+            con, alloc, offset, count, len, sizeBytes, dataType);
+    PER_ARRAY_TYPE(0, rsAllocation1DRead, con, alloc, offset, lod, count, ptr, sizeBytes);
 }
 
 static void
-nAllocationRead_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jbyteArray data)
+nAllocationRead2D(JNIEnv *_env, jobject _this, RsContext con, jint _alloc, jint xoff, jint yoff, jint lod, jint _face,
+                  jint w, jint h, jobject data, int sizeBytes, int dataType)
 {
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
-    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
-    jsize length = _env->GetArrayLength(data);
-    rsAllocationRead(con, (RsAllocation)alloc, ptr, length * sizeof(char));
-    _env->ReleaseByteArrayElements(data, ptr, 0);
-}
-
-static void
-nAllocationRead_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jfloatArray data)
-{
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationRead_f, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
-    jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
-    jsize length = _env->GetArrayLength(data);
-    rsAllocationRead(con, (RsAllocation)alloc, ptr, length * sizeof(float));
-    _env->ReleaseFloatArrayElements(data, ptr, 0);
+    RsAllocation *alloc = (RsAllocation *)_alloc;
+    RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
+    LOG_API("nAllocation2DRead, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)",
+            con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
+    PER_ARRAY_TYPE(0, rsAllocation2DRead, con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
 }
 
 static jint
@@ -1613,25 +1559,15 @@
 {"rsnAllocationSetSurface",          "(IILandroid/view/Surface;)V",           (void*)nAllocationSetSurface },
 {"rsnAllocationIoSend",              "(II)V",                                 (void*)nAllocationIoSend },
 {"rsnAllocationIoReceive",           "(II)V",                                 (void*)nAllocationIoReceive },
-{"rsnAllocationData1D",              "(IIIII[II)V",                           (void*)nAllocationData1D_i },
-{"rsnAllocationData1D",              "(IIIII[SI)V",                           (void*)nAllocationData1D_s },
-{"rsnAllocationData1D",              "(IIIII[BI)V",                           (void*)nAllocationData1D_b },
-{"rsnAllocationData1D",              "(IIIII[FI)V",                           (void*)nAllocationData1D_f },
+{"rsnAllocationData1D",              "(IIIIILjava/lang/Object;II)V",          (void*)nAllocationData1D },
 {"rsnAllocationElementData1D",       "(IIIII[BI)V",                           (void*)nAllocationElementData1D },
-{"rsnAllocationData2D",              "(IIIIIIII[II)V",                        (void*)nAllocationData2D_i },
-{"rsnAllocationData2D",              "(IIIIIIII[SI)V",                        (void*)nAllocationData2D_s },
-{"rsnAllocationData2D",              "(IIIIIIII[BI)V",                        (void*)nAllocationData2D_b },
-{"rsnAllocationData2D",              "(IIIIIIII[FI)V",                        (void*)nAllocationData2D_f },
+{"rsnAllocationData2D",              "(IIIIIIIILjava/lang/Object;II)V",       (void*)nAllocationData2D },
 {"rsnAllocationData2D",              "(IIIIIIIIIIIII)V",                      (void*)nAllocationData2D_alloc },
-{"rsnAllocationData3D",              "(IIIIIIIII[II)V",                       (void*)nAllocationData3D_i },
-{"rsnAllocationData3D",              "(IIIIIIIII[SI)V",                       (void*)nAllocationData3D_s },
-{"rsnAllocationData3D",              "(IIIIIIIII[BI)V",                       (void*)nAllocationData3D_b },
-{"rsnAllocationData3D",              "(IIIIIIIII[FI)V",                       (void*)nAllocationData3D_f },
+{"rsnAllocationData3D",              "(IIIIIIIIILjava/lang/Object;II)V",      (void*)nAllocationData3D },
 {"rsnAllocationData3D",              "(IIIIIIIIIIIIII)V",                     (void*)nAllocationData3D_alloc },
-{"rsnAllocationRead",                "(II[I)V",                               (void*)nAllocationRead_i },
-{"rsnAllocationRead",                "(II[S)V",                               (void*)nAllocationRead_s },
-{"rsnAllocationRead",                "(II[B)V",                               (void*)nAllocationRead_b },
-{"rsnAllocationRead",                "(II[F)V",                               (void*)nAllocationRead_f },
+{"rsnAllocationRead",                "(IILjava/lang/Object;I)V",              (void*)nAllocationRead },
+{"rsnAllocationRead1D",              "(IIIIILjava/lang/Object;II)V",          (void*)nAllocationRead1D },
+{"rsnAllocationRead2D",              "(IIIIIIIILjava/lang/Object;II)V",       (void*)nAllocationRead2D },
 {"rsnAllocationGetType",             "(II)I",                                 (void*)nAllocationGetType},
 {"rsnAllocationResize1D",            "(III)V",                                (void*)nAllocationResize1D },
 {"rsnAllocationGenerateMipmaps",     "(II)V",                                 (void*)nAllocationGenerateMipmaps },
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 67835a4..48613fe 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -76,7 +76,8 @@
     renderer->setupDrawShader();
     renderer->setupDrawBlending(true, mode);
     renderer->setupDrawProgram();
-    renderer->setupDrawModelView(x, y, x, y, pureTranslate, true);
+    renderer->setupDrawModelView(kModelViewMode_Translate, false,
+            0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
     // Calling setupDrawTexture with the name 0 will enable the
     // uv attributes and increase the texture unit count
     // texture binding will be performed by the font renderer as
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 29030d2..9b82013 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1074,7 +1074,13 @@
         }
     } else if (!rect.isEmpty()) {
         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+
+        save(0);
+        // the layer contains screen buffer content that shouldn't be alpha modulated
+        // (and any necessary alpha modulation was handled drawing into the layer)
+        mSnapshot->alpha = 1.0f;
         composeLayerRect(layer, rect, true);
+        restore();
     }
 
     dirtyClip();
@@ -1114,10 +1120,12 @@
         const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
 
         layer->setFilter(GL_NEAREST);
-        setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
+                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
     } else {
         layer->setFilter(GL_LINEAR);
-        setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
+        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
+                rect.left, rect.top, rect.right, rect.bottom);
     }
     setupDrawTextureTransformUniforms(layer->getTexTransform());
     setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
@@ -1229,10 +1237,12 @@
             const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f);
 
             layer->setFilter(GL_NEAREST);
-            setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
+            setupDrawModelView(kModelViewMode_Translate, false,
+                    x, y, x + rect.getWidth(), y + rect.getHeight(), true);
         } else {
             layer->setFilter(GL_LINEAR);
-            setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
+            setupDrawModelView(kModelViewMode_Translate, false,
+                    rect.left, rect.top, rect.right, rect.bottom);
         }
         setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
 
@@ -1343,7 +1353,7 @@
     }
 }
 
-void OpenGLRenderer::drawIndexedQuads(Vertex* mesh, GLsizei quadsCount) {
+void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
     GLsizei elementsCount = quadsCount * 6;
     while (elementsCount > 0) {
         GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
@@ -1395,9 +1405,10 @@
         setupDrawBlending(true, SkXfermode::kClear_Mode);
         setupDrawProgram();
         setupDrawPureColorUniforms();
-        setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
+        setupDrawModelView(kModelViewMode_Translate, false,
+                0.0f, 0.0f, 0.0f, 0.0f, true);
 
-        drawIndexedQuads(&mesh[0], count);
+        issueIndexedQuadDraw(&mesh[0], count);
 
         if (scissorChanged) mCaches.enableScissor();
     } else {
@@ -1862,39 +1873,20 @@
     mTrackDirtyRegions = false;
 }
 
-void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float right, float bottom,
-        bool ignoreTransform) {
+void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
+        float left, float top, float right, float bottom, bool ignoreTransform) {
     mModelView.loadTranslate(left, top, 0.0f);
-    if (!ignoreTransform) {
-        mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform());
-        if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform());
-    } else {
-        mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity());
-        if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
-    }
-}
-
-void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) {
-    mCaches.currentProgram->set(mOrthoMatrix, mat4::identity(), currentTransform(), offset);
-}
-
-void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom,
-        bool ignoreTransform, bool ignoreModelView) {
-    if (!ignoreModelView) {
-        mModelView.loadTranslate(left, top, 0.0f);
+    if (mode == kModelViewMode_TranslateAndScale) {
         mModelView.scale(right - left, bottom - top, 1.0f);
-    } else {
-        mModelView.loadIdentity();
     }
+
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
     if (!ignoreTransform) {
-        mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform());
-        if (mTrackDirtyRegions && dirty) {
-            dirtyLayer(left, top, right, bottom, currentTransform());
-        }
+        mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform(), offset);
+        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform());
     } else {
-        mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity());
-        if (mTrackDirtyRegions && dirty) dirtyLayer(left, top, right, bottom);
+        mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity(), offset);
+        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
     }
 }
 
@@ -1913,20 +1905,19 @@
 void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
     if (mDrawModifiers.mShader) {
         if (ignoreTransform) {
-            mModelView.loadInverse(currentTransform());
+            // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
+            // because it was built into modelView / the geometry, and the SkiaShader needs to
+            // compensate.
+            mat4 modelViewWithoutTransform;
+            modelViewWithoutTransform.loadInverse(currentTransform());
+            modelViewWithoutTransform.multiply(mModelView);
+            mModelView.load(modelViewWithoutTransform);
         }
         mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
                 mModelView, *mSnapshot, &mTextureUnit);
     }
 }
 
-void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
-    if (mDrawModifiers.mShader) {
-        mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
-                mat4::identity(), *mSnapshot, &mTextureUnit);
-    }
-}
-
 void OpenGLRenderer::setupDrawColorFilterUniforms() {
     if (mDrawModifiers.mColorFilter) {
         mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram);
@@ -2115,12 +2106,14 @@
         drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
                 texture->id, paint != NULL, color, alpha, mode,
                 &vertices[0].x, &vertices[0].u,
-                GL_TRIANGLES, bitmapCount * 6, true, true, false);
+                GL_TRIANGLES, bitmapCount * 6, true,
+                kModelViewMode_Translate, false);
     } else {
         drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
                 texture->id, alpha / 255.0f, mode, texture->blend,
                 &vertices[0].x, &vertices[0].u,
-                GL_TRIANGLES, bitmapCount * 6, false, true, 0, true, false);
+                GL_TRIANGLES, bitmapCount * 6, false, true, 0,
+                kModelViewMode_Translate, false);
     }
 
     return DrawGlInfo::kStatusDrew;
@@ -2297,7 +2290,7 @@
     setupDrawBlending(true, mode, false);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, false);
+    setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
     setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
@@ -2458,22 +2451,21 @@
             }
         }
 
+        bool ignoreTransform = false;
         if (CC_LIKELY(pureTranslate)) {
             const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f);
             const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f);
 
             right = x + right - left;
             bottom = y + bottom - top;
-            drawIndexedTextureMesh(x, y, right, bottom, texture->id, alpha / 255.0f,
-                    mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
-                    GL_TRIANGLES, mesh->indexCount, false, true,
-                    mCaches.patchCache.getMeshBuffer(), true, !mesh->hasEmptyQuads);
-        } else {
-            drawIndexedTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
-                    mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
-                    GL_TRIANGLES, mesh->indexCount, false, false,
-                    mCaches.patchCache.getMeshBuffer(), true, !mesh->hasEmptyQuads);
+            left = x;
+            top = y;
+            ignoreTransform = true;
         }
+        drawIndexedTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
+                mode, texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
+                GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
+                mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
     }
 
     return DrawGlInfo::kStatusDrew;
@@ -2500,13 +2492,15 @@
 
     drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
             mode, texture->blend, &vertices[0].x, &vertices[0].u,
-            GL_TRIANGLES, indexCount, false, true, 0, true, false);
+            GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
 
     return DrawGlInfo::kStatusDrew;
 }
 
 status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPaint* paint,
         bool useOffset) {
+    // not missing call to quickReject/dirtyLayer, always done at a higher level
+
     if (!vertexBuffer.getVertexCount()) {
         // no vertices to draw
         return DrawGlInfo::kStatusDone;
@@ -2524,10 +2518,10 @@
     setupDrawShader();
     setupDrawBlending(isAA, mode);
     setupDrawProgram();
-    setupDrawModelViewIdentity(useOffset);
+    setupDrawModelView(kModelViewMode_Translate, useOffset, 0, 0, 0, 0);
     setupDrawColorUniforms();
     setupDrawColorFilterUniforms();
-    setupDrawShaderIdentityUniforms();
+    setupDrawShaderUniforms();
 
     void* vertices = vertexBuffer.getBuffer();
     bool force = mCaches.unbindMeshBuffer();
@@ -2824,7 +2818,8 @@
     setupDrawShader();
     setupDrawBlending(true, mode);
     setupDrawProgram();
-    setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height);
+    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
+            sx, sy, sx + shadow->width, sy + shadow->height);
     setupDrawTexture(shadow->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
@@ -3105,11 +3100,11 @@
                 int ty = (int) floorf(y + currentTransform().getTranslateY() + 0.5f);
 
                 layer->setFilter(GL_NEAREST);
-                setupDrawModelViewTranslate(tx, ty,
+                setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
                         tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
             } else {
                 layer->setFilter(GL_LINEAR);
-                setupDrawModelViewTranslate(x, y,
+                setupDrawModelView(kModelViewMode_Translate, false, x, y,
                         x + layer->layer.getWidth(), y + layer->layer.getHeight());
             }
 
@@ -3255,7 +3250,8 @@
     setupDrawShader();
     setupDrawBlending(true, mode);
     setupDrawProgram();
-    setupDrawModelView(x, y, x + texture->width, y + texture->height);
+    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
+            x, y, x + texture->width, y + texture->height);
     setupDrawTexture(texture->id);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
@@ -3372,7 +3368,8 @@
     setupDrawBlending(mode);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, ignoreTransform, true);
+    setupDrawModelView(kModelViewMode_Translate, false,
+            0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
     setupDrawColorUniforms();
     setupDrawShaderUniforms();
     setupDrawColorFilterUniforms();
@@ -3381,7 +3378,7 @@
         dirtyLayer(left, top, right, bottom, currentTransform());
     }
 
-    drawIndexedQuads(&mesh[0], count / 4);
+    issueIndexedQuadDraw(&mesh[0], count / 4);
 
     return DrawGlInfo::kStatusDrew;
 }
@@ -3400,7 +3397,8 @@
     setupDrawColorFilter();
     setupDrawBlending(mode);
     setupDrawProgram();
-    setupDrawModelView(left, top, right, bottom, ignoreTransform);
+    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
+            left, top, right, bottom, ignoreTransform);
     setupDrawColorUniforms();
     setupDrawShaderUniforms(ignoreTransform);
     setupDrawColorFilterUniforms();
@@ -3458,7 +3456,8 @@
 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
+        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
+        ModelViewMode modelViewMode, bool dirty) {
 
     setupDraw();
     setupDrawWithTexture();
@@ -3467,11 +3466,7 @@
     setupDrawBlending(blend, mode, swapSrcDst);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
-    if (!ignoreScale) {
-        setupDrawModelView(left, top, right, bottom, ignoreTransform);
-    } else {
-        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
-    }
+    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
@@ -3483,7 +3478,8 @@
 void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
+        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
+        ModelViewMode modelViewMode, bool dirty) {
 
     setupDraw();
     setupDrawWithTexture();
@@ -3492,11 +3488,7 @@
     setupDrawBlending(blend, mode, swapSrcDst);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
-    if (!ignoreScale) {
-        setupDrawModelView(left, top, right, bottom, ignoreTransform);
-    } else {
-        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
-    }
+    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
@@ -3508,7 +3500,7 @@
 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
         GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool ignoreTransform, bool ignoreScale, bool dirty) {
+        bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
 
     setupDraw();
     setupDrawWithTexture(true);
@@ -3520,15 +3512,11 @@
     setupDrawBlending(true, mode);
     setupDrawProgram();
     if (!dirty) setupDrawDirtyRegionsDisabled();
-    if (!ignoreScale) {
-        setupDrawModelView(left, top, right, bottom, ignoreTransform);
-    } else {
-        setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
-    }
+    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
     setupDrawTexture(texture);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
-    setupDrawShaderUniforms();
+    setupDrawShaderUniforms(ignoreTransform);
     setupDrawMesh(vertices, texCoords);
 
     glDrawArrays(drawMode, 0, elementsCount);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 6e9c747..febf14a 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,6 +98,24 @@
     kClipSide_ConservativeFull = 0x1F
 };
 
+/**
+ * Defines additional transformation that should be applied by the model view matrix, beyond that of
+ * the currentTransform()
+ */
+enum ModelViewMode {
+    /**
+     * Used when the model view should simply translate geometry passed to the shader. The resulting
+     * matrix will be a simple translation.
+     */
+    kModelViewMode_Translate = 0,
+
+    /**
+     * Used when the model view should translate and scale geometry. The resulting matrix will be a
+     * translation + scale. This is frequently used together with VBO 0, the (0,0,1,1) rect.
+     */
+    kModelViewMode_TranslateAndScale = 1,
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // Renderer
 ///////////////////////////////////////////////////////////////////////////////
@@ -829,32 +847,33 @@
      * @param swapSrcDst Whether or not the src and dst blending operations should be swapped
      * @param ignoreTransform True if the current transform should be ignored
      * @param vbo The VBO used to draw the mesh
-     * @param ignoreScale True if the model view matrix should not be scaled
+     * @param modelViewMode Defines whether the model view matrix should be scaled
      * @param dirty True if calling this method should dirty the current layer
      */
     void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
             float alpha, SkXfermode::Mode mode, bool blend,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
             bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
-            bool ignoreScale = false, bool dirty = true);
+            ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
 
     void drawIndexedTextureMesh(float left, float top, float right, float bottom, GLuint texture,
             float alpha, SkXfermode::Mode mode, bool blend,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
             bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
-            bool ignoreScale = false, bool dirty = true);
+            ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
 
     void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
             GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode,
             GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-            bool ignoreTransform, bool ignoreScale = false, bool dirty = true);
+            bool ignoreTransform, ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale,
+            bool dirty = true);
 
     /**
      * Draws the specified list of vertices as quads using indexed GL_TRIANGLES.
      * If the number of vertices to draw exceeds the number of indices we have
      * pre-allocated, this method will generate several glDrawElements() calls.
      */
-    void drawIndexedQuads(Vertex* mesh, GLsizei quadsCount);
+    void issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount);
 
     /**
      * Draws text underline and strike-through if needed.
@@ -975,14 +994,26 @@
             bool swapSrcDst = false);
     void setupDrawProgram();
     void setupDrawDirtyRegionsDisabled();
-    void setupDrawModelViewIdentity(bool offset = false);
-    void setupDrawModelView(float left, float top, float right, float bottom,
-            bool ignoreTransform = false, bool ignoreModelView = false);
-    void setupDrawModelViewTranslate(float left, float top, float right, float bottom,
-            bool ignoreTransform = false);
+
+    /**
+     * Setup the current program matrices based upon the nature of the geometry.
+     *
+     * @param mode If kModelViewMode_Translate, the geometry must be translated by the left and top
+     * parameters. If kModelViewMode_TranslateAndScale, the geometry that exists in the (0,0, 1,1)
+     * space must be scaled up and translated to fill the quad provided in (l,t,r,b). These
+     * transformations are stored in the modelView matrix and uploaded to the shader.
+     *
+     * @param offset Set to true if the the matrix should be fudged (translated) slightly to disambiguate
+     * geometry pixel positioning. See Vertex::gGeometryFudgeFactor.
+     *
+     * @param ignoreTransform Set to true if l,t,r,b coordinates already in layer space,
+     * currentTransform() will be ignored. (e.g. when drawing clip in layer coordinates to stencil,
+     * or when simple translation has been extracted)
+     */
+    void setupDrawModelView(ModelViewMode mode, bool offset,
+            float left, float top, float right, float bottom, bool ignoreTransform = false);
     void setupDrawColorUniforms();
     void setupDrawPureColorUniforms();
-    void setupDrawShaderIdentityUniforms();
     void setupDrawShaderUniforms(bool ignoreTransform = false);
     void setupDrawColorFilterUniforms();
     void setupDrawSimpleMesh();
@@ -1054,7 +1085,20 @@
     // Matrix used for ortho projection in shaders
     mat4 mOrthoMatrix;
 
-    // Model-view matrix used to position/size objects
+    /**
+     * Model-view matrix used to position/size objects
+     *
+     * Stores operation-local modifications to the draw matrix that aren't incorporated into the
+     * currentTransform().
+     *
+     * If generated with kModelViewMode_Translate, the mModelView will reflect an x/y offset,
+     * e.g. the offset in drawLayer(). If generated with kModelViewMode_TranslateAndScale,
+     * mModelView will reflect a translation and scale, e.g. the translation and scale required to
+     * make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height of a
+     * bitmap.
+     *
+     * Used as input to SkiaShader transformation.
+     */
     mat4 mModelView;
 
     // Number of saved states
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 1f5fefd..b836f50 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -2913,12 +2913,10 @@
             int index;
             if (isMuted()) {
                 index = 0;
-            } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
-                       (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
                        mAvrcpAbsVolSupported) {
                 index = (mIndexMax + 5)/10;
-            }
-            else {
+            } else {
                 index = (getIndex(device) + 5)/10;
             }
             AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
@@ -2943,6 +2941,9 @@
                 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
                     if (isMuted()) {
                         index = 0;
+                    } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
+                            mAvrcpAbsVolSupported) {
+                        index = (mIndexMax + 5)/10;
                     } else {
                         index = ((Integer)entry.getValue() + 5)/10;
                     }
@@ -3215,7 +3216,14 @@
             for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
                 if (streamType != streamState.mStreamType &&
                         mStreamVolumeAlias[streamType] == streamState.mStreamType) {
-                    mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType));
+                    // Make sure volume is also maxed out on A2DP device for aliased stream
+                    // that may have a different device selected
+                    int streamDevice = getDeviceForStream(streamType);
+                    if ((device != streamDevice) && mAvrcpAbsVolSupported &&
+                            ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+                        mStreamStates[streamType].applyDeviceVolume(device);
+                    }
+                    mStreamStates[streamType].applyDeviceVolume(streamDevice);
                 }
             }
 
@@ -3843,9 +3851,12 @@
         // address is not used for now, but may be used when multiple a2dp devices are supported
         synchronized (mA2dpAvrcpLock) {
             mAvrcpAbsVolSupported = support;
-            VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
             sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
-                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
+                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
+                    mStreamStates[AudioSystem.STREAM_RING], 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/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d134667..4be9cd6 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -115,6 +115,7 @@
             nativeParcel->setData(obj->data(), obj->dataSize());
             env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                     msg, ext1, ext2, jParcel);
+            env->DeleteLocalRef(jParcel);
         }
     } else {
         env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
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/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/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index dbb7301..334318e 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -1,7 +1,7 @@
 <?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="8016145283189546017">"Dispositivi di input"</string>
+    <string name="app_label" msgid="8016145283189546017">"Dispositivi di immissione"</string>
     <string name="keyboard_layouts_label" msgid="6688773268302087545">"Tastiera Android"</string>
     <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Inglese (UK)"</string>
     <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglese (USA)"</string>
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_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
index 8be15cb..b4847f0 100644
--- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -32,12 +32,10 @@
         android:id="@+id/carrier_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:singleLine="true"
         android:ellipsize="marquee"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textSize="@dimen/kg_status_line_font_size"
-        android:textColor="?android:attr/textColorSecondary"
-        android:textAllCaps="@bool/kg_use_all_caps" />
+        android:textColor="?android:attr/textColorSecondary" />
 
     <LinearLayout
         android:layout_width="match_parent"
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/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 65460fa..be07dcd 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -135,12 +135,12 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Κατάργηση"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Εσφαλμένος κωδικός PIN κάρτας SIM. Θα πρέπει να επικοινωνήσετε με την εταιρεία κινητής τηλεφωνίας που χρησιμοποιείτε για να ξεκλειδώσετε τη συσκευή σας."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Εσφαλμένος κωδικός PIN κάρτας SIM. Θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Εσφαλμένος κωδικός PIN κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER">%d</xliff:g> προσπάθεια. Στη συνέχεια, θα πρέπει να επικοινωνήσετε με την εταιρεία κινητής τηλεφωνίας που χρησιμοποιείτε για να ξεκλειδώσετε τη συσκευή σας."</item>
+    <item quantity="one" msgid="8134313997799638254">"Εσφαλμένος κωδικός PIN κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER">%d</xliff:g> προσπάθεια. Στη συνέχεια, θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</item>
     <item quantity="other" msgid="2215723361575359486">"Εσφαλμένος κωδικός PIN κάρτας SIM. Απομένουν <xliff:g id="NUMBER">%d</xliff:g> προσπάθειες."</item>
   </plurals>
-    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας που χρησιμοποιείτε."</string>
+    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Η κάρτα SIM δεν μπορεί να χρησιμοποιηθεί. Επικοινωνήστε με τον πάροχο κινητής τηλεφωνίας σας."</string>
   <plurals name="kg_password_wrong_puk_code">
     <item quantity="one" msgid="3256893607561060649">"Εσφαλμένος κωδικός PUK κάρτας SIM. Απομένει άλλη <xliff:g id="NUMBER">%d</xliff:g> προσπάθεια προτού δεν είναι πλέον δυνατή η χρήση της κάρτας SIM."</item>
     <item quantity="other" msgid="5477305226026342036">"Εσφαλμένος κωδικός PUK κάρτας SIM. Απομένουν <xliff:g id="NUMBER">%d</xliff:g> προσπάθειες προτού δεν είναι πλέον δυνατή η χρήση της κάρτας SIM."</item>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index e8013fa..38beca3 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -23,7 +23,7 @@
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Ingresa el código PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Escribe el código PUK de la tarjeta SIM y un nuevo código PIN."</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Código PUK de la tarjeta SIM"</string>
-    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Nuevo código de PIN de la tarjeta SIM"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Nuevo código PIN de la tarjeta SIM"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Toca para ingresar la contraseña"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Ingresar contraseña para desbloquear"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Ingresa el PIN para desbloquear"</string>
@@ -142,11 +142,11 @@
   </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"La tarjeta SIM no se puede utilizar. Comunícate con el proveedor."</string>
   <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"El código PUK de la tarjeta SIM es incorrecto. Te queda <xliff:g id="NUMBER">%d</xliff:g> intento antes de que la tarjeta SIM no se pueda utilizar de forma permanente."</item>
-    <item quantity="other" msgid="5477305226026342036">"El código PUK de la tarjeta SIM es incorrecto. Te quedan <xliff:g id="NUMBER">%d</xliff:g> intentos antes de que la tarjeta SIM no se pueda utilizar de forma permanente."</item>
+    <item quantity="one" msgid="3256893607561060649">"El código PUK de la tarjeta SIM es incorrecto. Te queda <xliff:g id="NUMBER">%d</xliff:g> intento antes de que la tarjeta SIM quede inutilizable permanentemente."</item>
+    <item quantity="other" msgid="5477305226026342036">"El código PUK de la tarjeta SIM es incorrecto. Te quedan <xliff:g id="NUMBER">%d</xliff:g> intentos antes de que la tarjeta SIM quede inutilizable permanentemente."</item>
   </plurals>
-    <string name="kg_password_pin_failed" msgid="6268288093558031564">"Ocurrió un error al intentar desbloquear la tarjeta SIM con el código PIN."</string>
-    <string name="kg_password_puk_failed" msgid="2838824369502455984">"Ocurrió un error al intentar desbloquear la tarjeta SIM con el código PUK."</string>
+    <string name="kg_password_pin_failed" msgid="6268288093558031564">"Error al desbloquear la tarjeta SIM con el PIN"</string>
+    <string name="kg_password_puk_failed" msgid="2838824369502455984">"Error al desbloquear la tarjeta SIM con el PUK"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Botón de pista anterior"</string>
     <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Botón de pista siguiente"</string>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index cd3b97e..7212e5e 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -135,15 +135,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Rimuovi"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codice PIN della SIM sbagliato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Codice PIN della SIM sbagliato. Hai <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo."</item>
-    <item quantity="other" msgid="2215723361575359486">"Codice PIN della SIM sbagliato. Hai <xliff:g id="NUMBER">%d</xliff:g> tentativi ancora a disposizione."</item>
+    <item quantity="one" msgid="8134313997799638254">"Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione, dopodiché dovrai contattare l\'operatore per sbloccare il dispositivo."</item>
+    <item quantity="other" msgid="2215723361575359486">"Codice PIN della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativi a disposizione."</item>
   </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM inutilizzabile. Contatta il tuo operatore."</string>
   <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Codice PUK della SIM sbagliato. Hai <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile."</item>
-    <item quantity="other" msgid="5477305226026342036">"Codice PUK della SIM sbagliato. Hai <xliff:g id="NUMBER">%d</xliff:g> tentativi ancora a disposizione prima che la SIM diventi definitivamente inutilizzabile."</item>
+    <item quantity="one" msgid="3256893607561060649">"Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile."</item>
+    <item quantity="other" msgid="5477305226026342036">"Codice PUK della SIM errato. Hai ancora <xliff:g id="NUMBER">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile."</item>
   </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operazione con PIN della SIM non riuscita."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operazione con PUK della SIM non riuscita."</string>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index 5412d6d..3d7af75 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -135,10 +135,10 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"ამოშლა"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-ის არასწორი PIN კოდი. თქვენი ახლა მოგიწევთ მოწყობილობის განსაბლოკად მიმართოთ ოპერატორს."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM-ის არასწორი PIN კოდი. თქვენ ახლა მოგიწევთ მოწყობილობის განსაბლოკად მიმართოთ ოპერატორს."</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"SIM-ის არასწორი PIN კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა, სანამ თქვენი მოწყობილობის განსაბლოკად ოპერატორთა მოგიწევდეთ მიმართვა."</item>
-    <item quantity="other" msgid="2215723361575359486">"არასწორი SIM-ის PIN კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა."</item>
+    <item quantity="one" msgid="8134313997799638254">"SIM-ის არასწორი PIN კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა, სანამ მოგიწევთ თქვენი მოწყობილობის განსაბლოკად ოპერატორთან დაკავშირება."</item>
+    <item quantity="other" msgid="2215723361575359486">"SIM-ის არასწორი PIN კოდი. თქვენ დაგრჩათ <xliff:g id="NUMBER">%d</xliff:g> მცდელობა."</item>
   </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM გამოუსადეგარია. დაუკავშირდით ოპერატორს."</string>
   <plurals name="kg_password_wrong_puk_code">
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index 51d260b..a6845bc 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -23,7 +23,7 @@
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Taip kod PIN"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Taip PUK SIM dan kod PIN baharu"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"Kod PUK SIM"</string>
-    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Kod PIN SIM baru"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Kod PIN SIM baharu"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Sentuh untuk menaip kata laluan"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Taip kata laluan untuk membuka kunci"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Taip PIN untuk membuka kunci"</string>
@@ -135,15 +135,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Alih keluar"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kod PIN SIM tidak betul, anda kini harus menghubungi pembawa anda untuk membuka kunci peranti anda."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kod PIN SIM tidak betul, jadi anda harus menghubungi pembawa anda untuk membuka kunci peranti."</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Kod PIN SIM tidak betul. anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan yang tinggal sebelum anda harus menghubungi pembawa anda untuk membuka kunci peranti anda."</item>
-    <item quantity="other" msgid="2215723361575359486">"Kod PIN SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan yang tinggal."</item>
+    <item quantity="one" msgid="8134313997799638254">"Kod PIN SIM tidak betul. Anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum anda harus menghubungi pembawa anda untuk membuka kunci peranti."</item>
+    <item quantity="other" msgid="2215723361575359486">"Kod PIN SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi."</item>
   </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM tidak boleh digunakan. Hubungi pembawa anda."</string>
   <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Kod PUK SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan yang tinggal sebelum SIM tidak boleh digunakan secara kekal."</item>
-    <item quantity="other" msgid="5477305226026342036">"Kod PUK SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan yang tinggal sebelum SIM tidak boleh digunakan secara kekal."</item>
+    <item quantity="one" msgid="3256893607561060649">"Kod PUK SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM tidak boleh digunakan secara kekal."</item>
+    <item quantity="other" msgid="5477305226026342036">"Kod PUK SIM tidak betul, anda mempunyai <xliff:g id="NUMBER">%d</xliff:g> percubaan lagi sebelum SIM tidak boleh digunakan secara kekal."</item>
   </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operasi PIN SIM gagal!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operasi PUK SIM gagal!"</string>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 3329b80..c25a772 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -21,9 +21,9 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Skriv inn PIN-kode"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Skriv inn PUK-koden for SIM og en ny PIN-kode"</string>
-    <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-koden for SIM"</string>
-    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Ny PIN-kode for SIM"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Skriv inn PUK-koden for SIM-kortet og en ny PIN-kode"</string>
+    <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"PUK-koden for SIM-kortet"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Ny PIN-kode for SIM-kortet"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Trykk for å skrive inn passord"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Skriv inn passord for å låse opp"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Skriv inn PIN-kode for å låse opp"</string>
@@ -135,18 +135,18 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Fjern"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Feil PIN-kode for SIM. Du må nå kontakte operatøren din for å låse opp enheten."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Feil PIN-kode for SIM-kortet. Du må nå kontakte operatøren din for å låse opp enheten."</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Feil PIN-kode for SIM. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før du må kontakte operatøren din for å låse opp enheten."</item>
-    <item quantity="other" msgid="2215723361575359486">"Feil PIN-kode for SIM. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen."</item>
+    <item quantity="one" msgid="8134313997799638254">"Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før du må kontakte operatøren din for å låse opp enheten."</item>
+    <item quantity="other" msgid="2215723361575359486">"Feil PIN-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen."</item>
   </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM-kortet er ubrukelig. Kontakt operatøren din."</string>
   <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Feil PUK-kode for SIM. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig."</item>
-    <item quantity="other" msgid="5477305226026342036">"Feil PUK-kode for SIM. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig."</item>
+    <item quantity="one" msgid="3256893607561060649">"Feil PUK-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig."</item>
+    <item quantity="other" msgid="5477305226026342036">"Feil PUK-kode for SIM-kortet. Du har <xliff:g id="NUMBER">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig."</item>
   </plurals>
-    <string name="kg_password_pin_failed" msgid="6268288093558031564">"PIN-handlingen for SIM mislyktes."</string>
-    <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-handlingen for SIM mislyktes."</string>
+    <string name="kg_password_pin_failed" msgid="6268288093558031564">"PIN-koden for SIM-kortet ble avvist."</string>
+    <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-koden for SIM-kortet ble avvist."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden er godkjent."</string>
     <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Forrige spor-knapp"</string>
     <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Neste spor-knapp"</string>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index e14fd39..1c7e88f 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -135,15 +135,15 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail.\n\n Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Eliminaţi"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codul PIN pentru cardul SIM este incorect, contactați operatorul pentru a vă debloca dispozitivul."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Codul PIN pentru cardul SIM este incorect. Contactați operatorul pentru a vă debloca dispozitivul."</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Codul PIN pentru cardul SIM este incorect, v-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare înainte de a contacta operatorul pentru a vă debloca dispozitivul."</item>
-    <item quantity="other" msgid="2215723361575359486">"Codul PIN pentru cardul SIM este incorect, v-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări."</item>
+    <item quantity="one" msgid="8134313997799638254">"Codul PIN pentru cardul SIM este incorect. V-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare, după care va trebui să contactați operatorul pentru a vă debloca dispozitivul."</item>
+    <item quantity="other" msgid="2215723361575359486">"Codul PIN pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări."</item>
   </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Cardul SIM nu poate fi utilizat. Contactați operatorul."</string>
   <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Codul PUK pentru cardul SIM este incorect, v-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv."</item>
-    <item quantity="other" msgid="5477305226026342036">"Codul PUK pentru cardul SIM este incorect, v-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări până când cardul SIM va deveni inutilizabil definitiv."</item>
+    <item quantity="one" msgid="3256893607561060649">"Codul PUK pentru cardul SIM este incorect. V-a mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv."</item>
+    <item quantity="other" msgid="5477305226026342036">"Codul PUK pentru cardul SIM este incorect. V-au mai rămas <xliff:g id="NUMBER">%d</xliff:g> încercări până când cardul SIM va deveni inutilizabil definitiv."</item>
   </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Deblocarea cu ajutorul codului PIN pentru cardul SIM nu a reușit!"</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Deblocarea cu ajutorul codului PUK pentru cardul SIM nu a reușit!"</string>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index f51af4b..b0ec84e 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -137,12 +137,12 @@
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Odstrani"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Napačna koda PIN kartice SIM. Zdaj se boste morali za odklenitev naprave obrniti na operaterja."</string>
   <plurals name="kg_password_wrong_pin_code">
-    <item quantity="one" msgid="8134313997799638254">"Napačna koda PIN kartice SIM. Imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem se boste morali za odklenitev naprave obrniti na operaterja."</item>
+    <item quantity="one" msgid="8134313997799638254">"Napačna koda PIN kartice SIM. Na voljo imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem se boste morali za odklenitev naprave obrniti na operaterja."</item>
     <item quantity="other" msgid="2215723361575359486">"Napačna koda PIN kartice SIM. Poskusite lahko še <xliff:g id="NUMBER">%d</xliff:g>-krat."</item>
   </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Kartica SIM ni več uporabna. Obrnite se na operaterja."</string>
   <plurals name="kg_password_wrong_puk_code">
-    <item quantity="one" msgid="3256893607561060649">"Napačna koda PUK kartice SIM. Imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem bo kartica SIM postala trajno neuporabna."</item>
+    <item quantity="one" msgid="3256893607561060649">"Napačna koda PUK kartice SIM. Na voljo imate še <xliff:g id="NUMBER">%d</xliff:g> poskus. Potem bo kartica SIM postala trajno neuporabna."</item>
     <item quantity="other" msgid="5477305226026342036">"Napačna koda PUK kartice SIM. Poskusite lahko še <xliff:g id="NUMBER">%d</xliff:g>-krat. Potem bo kartica SIM postala trajno neuporabna."</item>
   </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Postopek za odklepanje s kodo PIN kartice SIM ni uspel."</string>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index 2dc7304..c7abd98 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -145,8 +145,8 @@
     <item quantity="one" msgid="3256893607561060649">"Msimbo wa PUK ya SIM usio sahihi, umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g> kabla ya SIM kuacha kutumika kabisa."</item>
     <item quantity="other" msgid="5477305226026342036">"Msimbo wa PUK ya SIM usio sahihi, umesalia na majaribio <xliff:g id="NUMBER">%d</xliff:g> kabla ya SIM kuacha kutumika kabisa."</item>
   </plurals>
-    <string name="kg_password_pin_failed" msgid="6268288093558031564">"Operesheni ya PIN ya SIM imeshindwa!"</string>
-    <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operesheni ya PUK ya SIM imeshindwa!"</string>
+    <string name="kg_password_pin_failed" msgid="6268288093558031564">"Utendakazi wa PIN ya SIM umeshindwa!"</string>
+    <string name="kg_password_puk_failed" msgid="2838824369502455984">"Utendakazi wa PUK ya SIM umeshindwa!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Msimbo Umekubaliwa!"</string>
     <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"Kitufe cha wimbo wa awali"</string>
     <string name="keyguard_transport_next_description" msgid="4299258300283778305">"Kitufe cha wimbo unaofuata"</string>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 2eabdb7..a44f9fe 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -145,8 +145,8 @@
     <item quantity="one" msgid="3256893607561060649">"รหัส PUK ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร"</item>
     <item quantity="other" msgid="5477305226026342036">"รหัส PUK ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร"</item>
   </plurals>
-    <string name="kg_password_pin_failed" msgid="6268288093558031564">"การดำเนินการ PIN ของซิมล้มเหลว!"</string>
-    <string name="kg_password_puk_failed" msgid="2838824369502455984">"การดำเนินการ PUK ของซิมล้มเหลว!"</string>
+    <string name="kg_password_pin_failed" msgid="6268288093558031564">"การปลดล็อกด้วย PIN ของซิมล้มเหลว!"</string>
+    <string name="kg_password_puk_failed" msgid="2838824369502455984">"การปลดล็อกด้วย PUK ของซิมล้มเหลว!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"รหัสได้รับการยอมรับ!"</string>
     <string name="keyguard_transport_prev_description" msgid="8229108430245669854">"ปุ่มแทร็กก่อนหน้า"</string>
     <string name="keyguard_transport_next_description" msgid="4299258300283778305">"ปุ่มแทร็กถัดไป"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/CameraWidgetFrame.java
index 7d1f24f..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
@@ -243,11 +243,12 @@
         final float pvTransX = pvWidth < thisWidth ? (thisWidth - pvWidth) / 2 : 0;
         final float pvTransY = pvHeight < thisHeight ? (thisHeight - pvHeight) / 2 : 0;
 
-        mPreview.setPivotX(0);
+        final boolean isRtl = mPreview.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        mPreview.setPivotX(isRtl ? mPreview.width : 0);
         mPreview.setPivotY(0);
         mPreview.setScaleX(pvScale);
         mPreview.setScaleY(pvScale);
-        mPreview.setTranslationX(pvTransX);
+        mPreview.setTranslationX((isRtl ? -1 : 1) * pvTransX);
         mPreview.setTranslationY(pvTransY);
 
         mRenderedSize.set(width, height);
@@ -417,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() {
@@ -512,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/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
index c33f174..88558cd 100644
--- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -17,14 +17,18 @@
 package com.android.keyguard;
 
 import android.content.Context;
+import android.text.method.SingleLineTransformationMethod;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.TextView;
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
 
+import java.util.Locale;
+
 public class CarrierText extends TextView {
     private static CharSequence mSeparator;
 
@@ -77,6 +81,8 @@
     public CarrierText(Context context, AttributeSet attrs) {
         super(context, attrs);
         mLockPatternUtils = new LockPatternUtils(mContext);
+        boolean useAllCaps = mContext.getResources().getBoolean(R.bool.kg_use_all_caps);
+        setTransformationMethod(new CarrierTextTransformationMethod(mContext, useAllCaps));
     }
 
     protected void updateCarrierText(State simState, CharSequence plmn, CharSequence spn) {
@@ -258,4 +264,25 @@
 
         return mContext.getText(carrierHelpTextId);
     }
+
+    private class CarrierTextTransformationMethod extends SingleLineTransformationMethod {
+        private final Locale mLocale;
+        private final boolean mAllCaps;
+
+        public CarrierTextTransformationMethod(Context context, boolean allCaps) {
+            mLocale = context.getResources().getConfiguration().locale;
+            mAllCaps = allCaps;
+        }
+
+        @Override
+        public CharSequence getTransformation(CharSequence source, View view) {
+            source = super.getTransformation(source, view);
+
+            if (mAllCaps && source != null) {
+                source = source.toString().toUpperCase(mLocale);
+            }
+
+            return source;
+        }
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java
index 677f1f1..2ee21acd 100644
--- a/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java
+++ b/packages/Keyguard/src/com/android/keyguard/ChallengeLayout.java
@@ -39,7 +39,7 @@
      *
      * @param b true to show, false to hide
      */
-    void showChallenge(boolean b);
+    void showChallenge(boolean show);
 
     /**
      * Show the bouncer challenge. This may block access to other child views.
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
index 9a1aa5b..0a915ea 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java
@@ -99,6 +99,11 @@
 
     public void launchCamera(Handler worker, Runnable onSecureCameraStarted) {
         LockPatternUtils lockPatternUtils = getLockPatternUtils();
+
+        // Workaround to avoid camera release/acquisition race when resuming face unlock
+        // after showing lockscreen camera (bug 11063890).
+        KeyguardUpdateMonitor.getInstance(getContext()).setAlternateUnlockEnabled(false);
+
         if (lockPatternUtils.isSecure()) {
             // Launch the secure version of the camera
             if (wouldLaunchResolverActivity(SECURE_CAMERA_INTENT)) {
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/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index fdc06a6..1bae9b8 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -218,7 +218,7 @@
         mTransportState = (dcs.clearing ? TRANSPORT_GONE :
             (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
 
-        if (DEBUG) Log.v(TAG, "Initial transport state: "
+        if (DEBUGXPORT) Log.v(TAG, "Initial transport state: "
                 + mTransportState + ", pbstate=" + dcs.playbackState);
     }
 
@@ -1369,7 +1369,7 @@
         }
     }
 
-    Runnable mSwitchPageRunnable = new Runnable() {
+    private final Runnable mSwitchPageRunnable = new Runnable() {
         @Override
         public void run() {
            showAppropriateWidgetPage();
@@ -1438,7 +1438,7 @@
         mAppWidgetToShow = ss.appWidgetToShow;
         setInsets(ss.insets);
         if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState);
-        post(mSwitchPageRunnable);
+        mSwitchPageRunnable.run();
     }
 
     @Override
@@ -1472,10 +1472,21 @@
     }
 
     private void showAppropriateWidgetPage() {
-        int state = mTransportState;
-        ensureTransportPresentOrRemoved(state);
-        int pageToShow = getAppropriateWidgetPage(state);
-        mAppWidgetContainer.setCurrentPage(pageToShow);
+        final int state = mTransportState;
+        final boolean transportAdded = ensureTransportPresentOrRemoved(state);
+        final int pageToShow = getAppropriateWidgetPage(state);
+        if (!transportAdded) {
+            mAppWidgetContainer.setCurrentPage(pageToShow);
+        } else if (state == TRANSPORT_VISIBLE) {
+            // If the transport was just added, we need to wait for layout to happen before
+            // we can set the current page.
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    mAppWidgetContainer.setCurrentPage(pageToShow);
+                }
+            });
+        }
     }
 
     /**
@@ -1499,12 +1510,11 @@
      *
      * @param state
      */
-    private void ensureTransportPresentOrRemoved(int state) {
+    private boolean ensureTransportPresentOrRemoved(int state) {
         final boolean showing = getWidgetPosition(R.id.keyguard_transport_control) != -1;
         final boolean visible = state == TRANSPORT_VISIBLE;
         final boolean shouldBeVisible = state == TRANSPORT_INVISIBLE && isMusicPlaying(state);
         if (!showing && (visible || shouldBeVisible)) {
-            if (DEBUGXPORT) Log.v(TAG, "add transport");
             // insert to left of camera if it exists, otherwise after right-most widget
             int lastWidget = mAppWidgetContainer.getChildCount() - 1;
             int position = 0; // handle no widget case
@@ -1512,13 +1522,16 @@
                 position = mAppWidgetContainer.isCameraPage(lastWidget) ?
                         lastWidget : lastWidget + 1;
             }
+            if (DEBUGXPORT) Log.v(TAG, "add transport at " + position);
             mAppWidgetContainer.addWidget(getOrCreateTransportControl(), position);
+            return true;
         } else if (showing && state == TRANSPORT_GONE) {
             if (DEBUGXPORT) Log.v(TAG, "remove transport");
             mAppWidgetContainer.removeWidget(getOrCreateTransportControl());
             mTransportControl = null;
             KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null);
         }
+        return false;
     }
 
     private CameraWidgetFrame findCameraPage() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
index 69075ec..751572c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMessageArea.java
@@ -177,6 +177,7 @@
 
     public KeyguardMessageArea(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setLayerType(LAYER_TYPE_HARDWARE, null); // work around nested unclipped SaveLayer bug
 
         mLockPatternUtils = new LockPatternUtils(context);
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index e39622a..9accbb4 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -46,9 +46,10 @@
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
     private static final String LOG_TAG = "KeyguardSimPinView";
     private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
+    public static final String TAG = "KeyguardSimPinView";
 
     private ProgressDialog mSimUnlockProgressDialog = null;
-    private volatile boolean mSimCheckInProgress;
+    private CheckSimPin mCheckSimPinThread;
 
     private AlertDialog mRemainingAttemptsDialog;
 
@@ -169,14 +170,17 @@
         @Override
         public void run() {
             try {
+                Log.v(TAG, "call supplyPinReportResult()");
                 final int[] result = ITelephony.Stub.asInterface(ServiceManager
                         .checkService("phone")).supplyPinReportResult(mPin);
+                Log.v(TAG, "supplyPinReportResult returned: " + result[0] + " " + result[1]);
                 post(new Runnable() {
                     public void run() {
                         onSimCheckResponse(result[0], result[1]);
                     }
                 });
             } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException for supplyPinReportResult:", e);
                 post(new Runnable() {
                     public void run() {
                         onSimCheckResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
@@ -229,9 +233,8 @@
 
         getSimUnlockProgressDialog().show();
 
-        if (!mSimCheckInProgress) {
-            mSimCheckInProgress = true; // there should be only one
-            new CheckSimPin(mPasswordEntry.getText().toString()) {
+        if (mCheckSimPinThread == null) {
+            mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText().toString()) {
                 void onSimCheckResponse(final int result, final int attemptsRemaining) {
                     post(new Runnable() {
                         public void run() {
@@ -263,11 +266,12 @@
                                 mPasswordEntry.setText("");
                             }
                             mCallback.userActivity(0);
-                            mSimCheckInProgress = false;
+                            mCheckSimPinThread = null;
                         }
                     });
                 }
-            }.start();
+            };
+            mCheckSimPinThread.start();
         }
     }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
index 31518a1..6e9e83e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -45,9 +45,10 @@
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
     private static final String LOG_TAG = "KeyguardSimPukView";
     private static final boolean DEBUG = KeyguardViewMediator.DEBUG;
+    public static final String TAG = "KeyguardSimPukView";
 
     private ProgressDialog mSimUnlockProgressDialog = null;
-    private volatile boolean mCheckInProgress;
+    private CheckSimPuk mCheckSimPukThread;
     private String mPukText;
     private String mPinText;
     private StateMachine mStateMachine = new StateMachine();
@@ -220,15 +221,17 @@
         @Override
         public void run() {
             try {
+                Log.v(TAG, "call supplyPukReportResult()");
                 final int[] result = ITelephony.Stub.asInterface(ServiceManager
                         .checkService("phone")).supplyPukReportResult(mPuk, mPin);
-
+                Log.v(TAG, "supplyPukReportResult returned: " + result[0] + " " + result[1]);
                 post(new Runnable() {
                     public void run() {
                         onSimLockChangedResponse(result[0], result[1]);
                     }
                 });
             } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException for supplyPukReportResult:", e);
                 post(new Runnable() {
                     public void run() {
                         onSimLockChangedResponse(PhoneConstants.PIN_GENERAL_FAILURE, -1);
@@ -295,9 +298,8 @@
     private void updateSim() {
         getSimUnlockProgressDialog().show();
 
-        if (!mCheckInProgress) {
-            mCheckInProgress = true;
-            new CheckSimPuk(mPukText, mPinText) {
+        if (mCheckSimPukThread == null) {
+            mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText) {
                 void onSimLockChangedResponse(final int result, final int attemptsRemaining) {
                     post(new Runnable() {
                         public void run() {
@@ -326,11 +328,12 @@
                                         + " attemptsRemaining=" + attemptsRemaining);
                                 mStateMachine.reset();
                             }
-                            mCheckInProgress = false;
+                            mCheckSimPukThread = null;
                         }
                     });
                 }
-            }.start();
+            };
+            mCheckSimPukThread.start();
         }
     }
 
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 c648177..169899f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewStateManager.java
@@ -120,21 +120,19 @@
 
     public void fadeOutSecurity(int duration) {
         ((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration)
-                .setListener(mPauseListener).start();
+                .setListener(mPauseListener);
     }
 
     public void fadeInSecurity(int duration) {
         ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration)
-                .setListener(mResumeListener).start();
+                .setListener(mResumeListener);
     }
 
     public void onPageBeginMoving() {
         if (mChallengeLayout.isChallengeOverlapping() &&
                 mChallengeLayout instanceof SlidingChallengeLayout) {
             SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
-            if (!mKeyguardWidgetPager.isWarping()) {
-                scl.fadeOutChallenge();
-            }
+            scl.fadeOutChallenge();
             mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
         }
         // We use mAppWidgetToShow to show a particular widget after you add it--
@@ -156,11 +154,12 @@
     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);
-            if (isCameraPage) {
-                scl.fadeOutChallenge();
-            }
             final int currentFlags = mKeyguardWidgetPager.getSystemUiVisibility();
             final int newFlags = isCameraPage ? (currentFlags | View.STATUS_BAR_DISABLE_SEARCH)
                     : (currentFlags & ~View.STATUS_BAR_DISABLE_SEARCH);
@@ -197,7 +196,7 @@
             boolean challengeOverlapping = mChallengeLayout.isChallengeOverlapping();
             if (challengeOverlapping && !newCurPage.isSmall()
                     && mPageListeningToSlider != newPageIndex) {
-                newCurPage.shrinkWidget();
+                newCurPage.shrinkWidget(true);
             }
         }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
index ab8a759..8ee9b61 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetFrame.java
@@ -375,10 +375,6 @@
         return mSmallFrameHeight;
     }
 
-    public void shrinkWidget() {
-        shrinkWidget(true);
-    }
-
     public void setWidgetLockedSmall(boolean locked) {
         if (locked) {
             setWidgetHeight(mSmallWidgetHeight);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
index 704af6e..99f7757 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardWidgetPager.java
@@ -194,7 +194,9 @@
 
     @Override
     public void onPageEndWarp() {
-        hideOutlinesAndSidePages();
+        // if we're moving to the warp page, then immediately hide the other widgets.
+        int duration = getPageWarpIndex() == getNextPage() ? 0 : -1;
+        animateOutlinesAndSidePages(false, duration);
         mViewStateManager.onPageEndWarp();
     }
 
@@ -669,7 +671,7 @@
                 // On the very first measure pass, if the challenge is showing, we need to make sure
                 // that the widget on the current page is small.
                 if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
-                    frame.shrinkWidget();
+                    frame.shrinkWidget(true);
                 }
             }
         }
diff --git a/packages/Keyguard/src/com/android/keyguard/PagedView.java b/packages/Keyguard/src/com/android/keyguard/PagedView.java
index 5df5d07..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)) {
@@ -2725,7 +2727,7 @@
     };
 
     private void cancelWarpAnimation(String msg, boolean abortAnimation) {
-        if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ")");
+        if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ",abort=" + abortAnimation + ")");
         if (abortAnimation) {
             // We're done with the animation and moving to a new page.  Let the scroller
             // take over the animation.
diff --git a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
index 7a9a1c8..3d515ce 100644
--- a/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
+++ b/packages/Keyguard/src/com/android/keyguard/SlidingChallengeLayout.java
@@ -1003,6 +1003,16 @@
         }
     }
 
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        // Focus security fileds before widgets.
+        if (mChallengeView != null &&
+                mChallengeView.requestFocus(direction, previouslyFocusedRect)) {
+            return true;
+        }
+        return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+    }
+
     public void computeScroll() {
         super.computeScroll();
 
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
new file mode 100644
index 0000000..3187cbe
--- /dev/null
+++ b/packages/PrintSpooler/res/values-ja/arrays.xml
@@ -0,0 +1,41 @@
+<?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>
+
+    <string-array name="pdf_printer_media_sizes" translatable="false">
+        <item>JIS_B10</item>
+        <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_EXEC</item>
+        <item>JPN_CHOU4</item>
+        <item>JPN_CHOU3</item>
+        <item>JPN_CHOU2</item>
+        <item>JPN_HAGAKI</item>
+        <item>JPN_OUFUKU</item>
+        <item>JPN_KAHU</item>
+        <item>JPN_KAKU2</item>
+        <item>JPN_YOU4</item>
+    </string-array>
+
+</resources>
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/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index f2e768a..d2613d0 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -93,6 +93,12 @@
     <!-- Title of the action bar button to got to add a printer. [CHAR LIMIT=25] -->
     <string name="print_add_printer">Add printer</string>
 
+    <!-- Title of the menu item to select a printer. [CHAR LIMIT=25] -->
+    <string name="print_select_printer">Select printer</string>
+
+    <!-- Title of the menu item to forget a printer. [CHAR LIMIT=25] -->
+    <string name="print_forget_printer">Forget printer</string>
+
     <!-- Utterance to announce a change in the number of matches during a search. This is spoken to a blind user. [CHAR LIMIT=none] -->
     <plurals name="print_search_result_count_utterance">
         <item quantity="one"><xliff:g id="count" example="1">%1$s</xliff:g> printer found</item>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
index 0601467..9831839 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -79,6 +79,8 @@
 
     private PrinterId mTrackedPrinter;
 
+    private boolean mPrintersUpdatedBefore;
+
     public FusedPrintersProvider(Context context) {
         super(context);
         mPersistenceManager = new PersistenceManager(context);
@@ -88,13 +90,14 @@
         mPersistenceManager.addPrinterAndWritePrinterHistory(printer);
     }
 
-    private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters) {
+    private void computeAndDeliverResult(ArrayMap<PrinterId, PrinterInfo> discoveredPrinters,
+            ArrayMap<PrinterId, PrinterInfo> favoritePrinters) {
         List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
 
         // Add the updated favorite printers.
-        final int favoritePrinterCount = mFavoritePrinters.size();
+        final int favoritePrinterCount = favoritePrinters.size();
         for (int i = 0; i < favoritePrinterCount; i++) {
-            PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
+            PrinterInfo favoritePrinter = favoritePrinters.valueAt(i);
             PrinterInfo updatedPrinter = discoveredPrinters.remove(
                     favoritePrinter.getId());
             if (updatedPrinter != null) {
@@ -123,8 +126,11 @@
         mPrinters.addAll(printers);
 
         if (isStarted()) {
-            // Deliver the printers.
+            // If stated deliver the new printers.
             deliverResult(printers);
+        } else {
+            // Otherwise, take a note for the change.
+            onContentChanged();
         }
     }
 
@@ -165,6 +171,8 @@
                     .getSystemService(Context.PRINT_SERVICE);
             mDiscoverySession = printManager.createPrinterDiscoverySession();
             mPersistenceManager.readPrinterHistory();
+        } else if (mPersistenceManager.isHistoryChanged()) {
+            mPersistenceManager.readPrinterHistory();
         }
         if (mPersistenceManager.isReadHistoryCompleted()
                 && !mDiscoverySession.isPrinterDiscoveryStarted()) {
@@ -176,7 +184,7 @@
                                 + mDiscoverySession.getPrinters().size()
                                 + " " + FusedPrintersProvider.this.hashCode());
                     }
-                    updatePrinters(mDiscoverySession.getPrinters());
+                    updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
                 }
             });
             final int favoriteCount = mFavoritePrinters.size();
@@ -187,15 +195,19 @@
             mDiscoverySession.startPrinterDisovery(printerIds);
             List<PrinterInfo> printers = mDiscoverySession.getPrinters();
             if (!printers.isEmpty()) {
-                updatePrinters(printers);
+                updatePrinters(printers, mFavoritePrinters);
             }
         }
     }
 
-    private void updatePrinters(List<PrinterInfo> printers) {
-        if (mPrinters.equals(printers)) {
+    private void updatePrinters(List<PrinterInfo> printers, List<PrinterInfo> favoritePrinters) {
+        if (mPrintersUpdatedBefore && mPrinters.equals(printers)
+                && mFavoritePrinters.equals(favoritePrinters)) {
             return;
         }
+
+        mPrintersUpdatedBefore = true;
+
         ArrayMap<PrinterId, PrinterInfo> printersMap =
                 new ArrayMap<PrinterId, PrinterInfo>();
         final int printerCount = printers.size();
@@ -203,7 +215,16 @@
             PrinterInfo printer = printers.get(i);
             printersMap.put(printer.getId(), printer);
         }
-        computeAndDeliverResult(printersMap);
+
+        ArrayMap<PrinterId, PrinterInfo> favoritePrintersMap =
+                new ArrayMap<PrinterId, PrinterInfo>();
+        final int favoritePrinterCount = favoritePrinters.size();
+        for (int i = 0; i < favoritePrinterCount; i++) {
+            PrinterInfo favoritePrinter = favoritePrinters.get(i);
+            favoritePrintersMap.put(favoritePrinter.getId(), favoritePrinter);
+        }
+
+        computeAndDeliverResult(printersMap, favoritePrintersMap);
     }
 
     @Override
@@ -264,6 +285,42 @@
         }
     }
 
+    public boolean isFavoritePrinter(PrinterId printerId) {
+        final int printerCount = mFavoritePrinters.size();
+        for (int i = 0; i < printerCount; i++) {
+            PrinterInfo favoritePritner = mFavoritePrinters.get(i);
+            if (favoritePritner.getId().equals(printerId)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void forgetFavoritePrinter(PrinterId printerId) {
+        List<PrinterInfo> newFavoritePrinters = null;
+
+        // Remove the printer from the favorites.
+        final int favoritePrinterCount = mFavoritePrinters.size();
+        for (int i = 0; i < favoritePrinterCount; i++) {
+            PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
+            if (favoritePrinter.getId().equals(printerId)) {
+                newFavoritePrinters = new ArrayList<PrinterInfo>();
+                newFavoritePrinters.addAll(mPrinters);
+                newFavoritePrinters.remove(i);
+                break;
+            }
+        }
+
+        // If we removed a favorite printer, we have work to do.
+        if (newFavoritePrinters != null) {
+            // Remove the printer from history and persist the latter.
+            mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId);
+
+            // Recompute and deliver the printers.
+            updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters);
+        }
+    }
+
     private final class PersistenceManager {
         private static final String PERSIST_FILE_NAME = "printer_history.xml";
 
@@ -281,13 +338,15 @@
 
         private final AtomicFile mStatePersistFile;
 
-        private List<PrinterInfo> mHistoricalPrinters;
+        private List<PrinterInfo> mHistoricalPrinters = new ArrayList<PrinterInfo>();
 
         private boolean mReadHistoryCompleted;
         private boolean mReadHistoryInProgress;
 
         private ReadTask mReadTask;
 
+        private volatile long mLastReadHistoryTimestamp;
+
         private PersistenceManager(Context context) {
             mStatePersistFile = new AtomicFile(new File(context.getFilesDir(),
                     PERSIST_FILE_NAME));
@@ -327,6 +386,27 @@
                     new ArrayList<PrinterInfo>(mHistoricalPrinters));
         }
 
+        @SuppressWarnings("unchecked")
+        public void removeHistoricalPrinterAndWritePrinterHistory(PrinterId printerId) {
+            boolean writeHistory = false;
+            final int printerCount = mHistoricalPrinters.size();
+            for (int i = printerCount - 1; i >= 0; i--) {
+                PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
+                if (historicalPrinter.getId().equals(printerId)) {
+                    mHistoricalPrinters.remove(i);
+                    writeHistory = true;
+                }
+            }
+            if (writeHistory) {
+                new WriteTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,
+                        new ArrayList<PrinterInfo>(mHistoricalPrinters));
+            }
+        }
+
+        public boolean isHistoryChanged() {
+            return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
+        }
+
         private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) {
             Map<PrinterId, PrinterRecord> recordMap =
                     new ArrayMap<PrinterId, PrinterRecord>();
@@ -423,11 +503,10 @@
                 mReadHistoryInProgress = false;
                 mReadHistoryCompleted = true;
 
-                // Deliver the favorites.
-                Map<PrinterId, PrinterInfo> discoveredPrinters = Collections.emptyMap();
-                computeAndDeliverResult(discoveredPrinters);
+                // Deliver the printers.
+                updatePrinters(mDiscoverySession.getPrinters(), mHistoricalPrinters);
 
-                // Start loading the available printers.
+                // Loading the available printers if needed.
                 loadInternal();
 
                 // We are done.
@@ -450,6 +529,8 @@
                     XmlPullParser parser = Xml.newPullParser();
                     parser.setInput(in, null);
                     parseState(parser, printers);
+                    // Take a note which version of the history was read.
+                    mLastReadHistoryTimestamp = mStatePersistFile.getBaseFile().lastModified();
                     return printers;
                 } catch (IllegalStateException ise) {
                     Slog.w(LOG_TAG, "Failed parsing ", ise);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 6d0ecd7..88403a3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -937,6 +937,7 @@
                             mPrintJobId, mCurrentPrinter);
 
                     if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) {
+                        mCapabilitiesTimeout.post();
                         updateUi();
                         return;
                     }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java
index 609ae64..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();
+            }
         }
     }
 
@@ -544,7 +548,7 @@
         final int printJobCount = mPrintJobs.size();
         for (int i = 0; i < printJobCount; i++) {
             PrintJobInfo printJob = mPrintJobs.get(i);
-            if (isActiveState(printJob.getState())
+            if (isActiveState(printJob.getState()) && printJob.getPrinterId() != null
                     && printJob.getPrinterId().getServiceName().equals(service)) {
                 return true;
             }
@@ -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/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
index 204c152..fe5920c 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java
@@ -46,6 +46,8 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -54,6 +56,7 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
 import android.widget.ArrayAdapter;
 import android.widget.BaseAdapter;
 import android.widget.Filter;
@@ -81,6 +84,8 @@
     private static final String FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS =
             "FRAGMRNT_ARGUMENT_PRINT_SERVICE_INFOS";
 
+    private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
+
     private final ArrayList<PrintServiceInfo> mAddPrinterServices =
             new ArrayList<PrintServiceInfo>();
 
@@ -127,6 +132,9 @@
         mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
             @Override
             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                if (!((DestinationAdapter) mListView.getAdapter()).isActionable(position)) {
+                    return;
+                }
                 PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
                 Activity activity = getActivity();
                 if (activity instanceof OnPrinterSelectedListener) {
@@ -138,6 +146,8 @@
             }
         });
 
+        registerForContextMenu(mListView);
+
         return content;
     }
 
@@ -185,6 +195,62 @@
     }
 
     @Override
+    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
+        if (view == mListView) {
+            final int position = ((AdapterContextMenuInfo) menuInfo).position;
+            PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
+
+            menu.setHeaderTitle(printer.getName());
+
+            // Add the select menu item if applicable.
+            if (printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE) {
+                MenuItem selectItem = menu.add(Menu.NONE, R.string.print_select_printer,
+                        Menu.NONE, R.string.print_select_printer);
+                Intent intent = new Intent();
+                intent.putExtra(EXTRA_PRINTER_ID, printer.getId());
+                selectItem.setIntent(intent);
+            }
+
+            // Add the forget menu item if applicable.
+            FusedPrintersProvider provider = (FusedPrintersProvider) (Loader<?>)
+                    getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER);
+            if (provider.isFavoritePrinter(printer.getId())) {
+                MenuItem forgetItem = menu.add(Menu.NONE, R.string.print_forget_printer,
+                        Menu.NONE, R.string.print_forget_printer);
+                Intent intent = new Intent();
+                intent.putExtra(EXTRA_PRINTER_ID, printer.getId());
+                forgetItem.setIntent(intent);
+            }
+        }
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.string.print_select_printer: {
+                PrinterId printerId = (PrinterId) item.getIntent().getParcelableExtra(
+                        EXTRA_PRINTER_ID);
+                Activity activity = getActivity();
+                if (activity instanceof OnPrinterSelectedListener) {
+                    ((OnPrinterSelectedListener) activity).onPrinterSelected(printerId);
+                } else {
+                    throw new IllegalStateException("the host activity must implement"
+                            + " OnPrinterSelectedListener");
+                }
+            } return true;
+
+            case R.string.print_forget_printer: {
+                PrinterId printerId = (PrinterId) item.getIntent().getParcelableExtra(
+                        EXTRA_PRINTER_ID);
+                FusedPrintersProvider provider = (FusedPrintersProvider) (Loader<?>)
+                        getLoaderManager().getLoader(LOADER_ID_PRINTERS_LOADER);
+                provider.forgetFavoritePrinter(printerId);
+            } return true;
+        }
+        return false;
+    }
+
+    @Override
     public void onResume() {
         updateAddPrintersAdapter();
         getActivity().invalidateOptionsMenu();
@@ -464,7 +530,7 @@
                         R.layout.printer_list_item, parent, false);
             }
 
-            convertView.setEnabled(isEnabled(position));
+            convertView.setEnabled(isActionable(position));
 
             CharSequence title = null;
             CharSequence subtitle = null;
@@ -506,8 +572,7 @@
             return convertView;
         }
 
-        @Override
-        public boolean isEnabled(int position) {
+        public boolean isActionable(int position) {
             PrinterInfo printer =  (PrinterInfo) getItem(position);
             return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
         }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ffb4c20..29e8d1d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -5,7 +5,6 @@
         >
 
     <!-- Standard permissions granted to the shell. -->
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.SEND_SMS" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
@@ -64,6 +63,7 @@
     <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
     <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" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
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/bg_protect.9.png b/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png
new file mode 100644
index 0000000..5bbfa4f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
index 2d8d074..693abf5 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_settings_normal.png
Binary files differ
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-land-hdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png
new file mode 100644
index 0000000..1a58144
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png
new file mode 100644
index 0000000..a12519e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-mdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png
new file mode 100644
index 0000000..ce41454
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png
new file mode 100644
index 0000000..b0b4561
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png b/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png
new file mode 100644
index 0000000..2856e09
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
index 399db00..15340d3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_settings_normal.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/bg_protect.9.png b/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png
new file mode 100644
index 0000000..72269f2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
index c0032e2..e3cc9b0 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_settings_normal.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/bg_protect.9.png b/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png
new file mode 100644
index 0000000..efc9b04
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/bg_protect.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
index a3cc08d..e15981a 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_settings_normal.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-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index b2ba25a..0c0be29 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -24,6 +24,7 @@
     android:id="@+id/recents_root"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
+    android:foreground="@drawable/bg_protect"
     systemui:recentItemLayout="@layout/status_bar_recent_item"
     >
     <FrameLayout
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/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index d7312df..eb66908 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -95,12 +95,12 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     />
-                <!-- battery must be padded below by 2px to match assets -->
+                <!-- battery must be padded below to match assets -->
                 <com.android.systemui.BatteryMeterView
                     android:id="@+id/battery"
                     android:layout_height="16dp"
                     android:layout_width="10.5dp"
-                    android:layout_marginBottom="2px"
+                    android:layout_marginBottom="0.33dp"
                     android:layout_marginStart="4dip"
                     />
             </LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
index e41475b..2f3968d 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -24,6 +24,7 @@
     android:id="@+id/recents_root"
     android:layout_height="match_parent"
     android:layout_width="match_parent"
+    android:foreground="@drawable/bg_protect"
     systemui:recentItemLayout="@layout/status_bar_recent_item"
     >
     <FrameLayout
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index ed9bc8f..cc8656f 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="quick_settings_inversion_label" msgid="1666358784283020762">"Kleur-omkeringmodus"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7054d15..1375bb7 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="quick_settings_inversion_label" msgid="1666358784283020762">"የተቃራኒ ቀለም ሁነታ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 70586de..8751d72 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="quick_settings_inversion_label" msgid="1666358784283020762">"وضع انعكاس اللون"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 10655d8..1f0a546 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 quick_settings_inversion_label (1666358784283020762) -->
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bb1f18b..da8f63e 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="quick_settings_inversion_label" msgid="1666358784283020762">"Режим на инвертиране на цветовете"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 1cd5e1d..d64bb33 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="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversió de color"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index ba72b81..034f92a 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="quick_settings_inversion_label" msgid="1666358784283020762">"Režim převrácení barev"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 30c41bf..e054ae7 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="quick_settings_inversion_label" msgid="1666358784283020762">"Farveinverteringstilstand"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index ff785be..926d3d1 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="quick_settings_inversion_label" msgid="1666358784283020762">"Farbinversionsmodus"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 0129a93..260c99d 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="quick_settings_inversion_label" msgid="1666358784283020762">"Λειτουργία αναστροφής χρώματος"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 1c22c86..8f73364 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="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 1c22c86..8f73364 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="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 86a6b96..277e188 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="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversión de color"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 200b066..fb7b530 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="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversión de color"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index aefeb9d..cc93ef5 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="quick_settings_inversion_label" msgid="1666358784283020762">"Värvide ümberpööramise režiim"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ea6c102..90082ba 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="quick_settings_inversion_label" msgid="1666358784283020762">"حالت وارونگی رنگ"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 2e9c5f3..4dc8304 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="quick_settings_inversion_label" msgid="1666358784283020762">"Käänteinen väritila"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a0cc012..c47edd5 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="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversion des couleurs"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 7b1e100..6e791a1 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="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversion des couleurs"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 59c5dbd..0099a94 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="quick_settings_inversion_label" msgid="1666358784283020762">"रंग व्युत्क्रम मोड"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 6d21e44..abccd4c8 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="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije boje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ca78170..e3fb0ab 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="quick_settings_inversion_label" msgid="1666358784283020762">"Színinvertálás mód"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 342c6be..eadea31 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="quick_settings_inversion_label" msgid="1666358784283020762">"Գունաշրջման ռեժիմ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 1d58eda9..0c7fbb4 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="quick_settings_inversion_label" msgid="1666358784283020762">"Mode inversi warna"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 4efe75c..2e65cf6 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="quick_settings_inversion_label" msgid="1666358784283020762">"Modalità inversione colori"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 0ed3f97..062d289 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="quick_settings_inversion_label" msgid="1666358784283020762">"מצב היפוך צבעים"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 0e0f027..560cf3a 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="quick_settings_inversion_label" msgid="1666358784283020762">"色反転モード"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 5d751fc..f932732 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="quick_settings_inversion_label" msgid="1666358784283020762">"ფერთა ინვერსიის რეჟიმი"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 22e1d92..cf2ae62 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="quick_settings_inversion_label" msgid="1666358784283020762">"របៀប​​បញ្ច្រាស​ពណ៌"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 9477bac..8aea2fc 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="quick_settings_inversion_label" msgid="1666358784283020762">"색상 반전 모드"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index d5ba666..ac4ad35 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="quick_settings_inversion_label" msgid="1666358784283020762">"ໂໝດສະລັບສີ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 3fae805..1aa2bce 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="quick_settings_inversion_label" msgid="1666358784283020762">"Spalvų inversijos režimas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 2a3a333..4be6253 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="quick_settings_inversion_label" msgid="1666358784283020762">"Krāsu inversijas režīms"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index bbcf943..c347846 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="quick_settings_inversion_label" msgid="1666358784283020762">"Өнгө урвуулах горим"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index aa81268..5ac78b2 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="quick_settings_inversion_label" msgid="1666358784283020762">"Mod penyongsangan warna"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 8e31781..52bf03c 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="quick_settings_inversion_label" msgid="1666358784283020762">"Modus for fargeinvertering"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 5d77c5d..8719c23 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 display"</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="quick_settings_inversion_label" msgid="1666358784283020762">"Modus voor kleurinversie"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6abaea0..266ab69 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="quick_settings_inversion_label" msgid="1666358784283020762">"Tryb odwrócenia kolorów"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1921581..99b908f 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="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversão de cor"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index d6e6d6e..6491723 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="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversão de cores"</string>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index dd5a231..5c3d5e2 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 606aff1..c8ddc47 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="quick_settings_inversion_label" msgid="1666358784283020762">"Mod de inversare a culorilor"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7f7198b..99c898e 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="quick_settings_inversion_label" msgid="1666358784283020762">"Инверсия цвета"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 3996f77..c5c9b38 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="quick_settings_inversion_label" msgid="1666358784283020762">"Režim prevrátenia farieb"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 637b5b9..d03df5c 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="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije barv"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 42fd7ac..9513090 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="quick_settings_inversion_label" msgid="1666358784283020762">"Режим инверзије боје"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 558c5b4..d9d4c16 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="quick_settings_inversion_label" msgid="1666358784283020762">"Färginverteringsläge"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a548110..ff635fc 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="quick_settings_inversion_label" msgid="1666358784283020762">"Hali ya ugeuzaji kinyume wa rangi"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 962fc7e..025c3e1 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="quick_settings_inversion_label" msgid="1666358784283020762">"โหมดการกลับสี"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3de0f06..273ce34 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="quick_settings_inversion_label" msgid="1666358784283020762">"Mode ng pag-invert ng kulay"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 948ae6c..c734a73 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -153,7 +153,7 @@
     <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Pil <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_airplane" msgid="4196876722090224753">"Uçak Modu <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="5749054971341882340">"Bluetooth <xliff:g id="STATE">%s</xliff:g>."</string>
-    <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Konum <xliff:g id="STATE">%s</xliff:g>."</string>
+    <string name="accessibility_quick_settings_location" msgid="4577282329866813100">"Konum: <xliff:g id="STATE">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm saati: <xliff:g id="TIME">%s</xliff:g>."</string>
     <string name="data_usage_disabled_dialog_3g_title" msgid="5257833881698644687">"2G-3G verileri devre dışı bırakıldı"</string>
     <string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G verileri devre dışı"</string>
@@ -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="quick_settings_inversion_label" msgid="1666358784283020762">"Renk ters çevirme modu"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index fe64274..ce1bec7 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="quick_settings_inversion_label" msgid="1666358784283020762">"Режим інверсії кольорів"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index fb4e377..44449c8 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="quick_settings_inversion_label" msgid="1666358784283020762">"Chế độ đảo ngược màu sắc"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c5708ac..5ffc73f 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="quick_settings_inversion_label" msgid="1666358784283020762">"颜色反转模式"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 2cbe82d..6f99b00 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="quick_settings_inversion_label" msgid="1666358784283020762">"色彩反轉模式"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5b205e1..9d42e8b 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="quick_settings_inversion_label" msgid="1666358784283020762">"彩色反轉模式"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 131eef5..b0ff794 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="quick_settings_inversion_label" msgid="1666358784283020762">"Imodi yokuguqulwa kombala"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 556a146..25202edf 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/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index b6e03e1..13aafb2 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -66,7 +66,7 @@
     private final RectF mFrame = new RectF();
     private final RectF mButtonFrame = new RectF();
     private final RectF mClipFrame = new RectF();
-    private final Rect mBoltFrame = new Rect();
+    private final RectF mBoltFrame = new RectF();
 
     private class BatteryTracker extends BroadcastReceiver {
         public static final int UNKNOWN_LEVEL = -1;
@@ -319,10 +319,10 @@
 
         if (tracker.plugged) {
             // draw the bolt
-            final int bl = (int)(mFrame.left + mFrame.width() / 4.5f);
-            final int bt = (int)(mFrame.top + mFrame.height() / 6f);
-            final int br = (int)(mFrame.right - mFrame.width() / 7f);
-            final int bb = (int)(mFrame.bottom - mFrame.height() / 10f);
+            final float bl = mFrame.left + mFrame.width() / 4.5f;
+            final float bt = mFrame.top + mFrame.height() / 6f;
+            final float br = mFrame.right - mFrame.width() / 7f;
+            final float bb = mFrame.bottom - mFrame.height() / 10f;
             if (mBoltFrame.left != bl || mBoltFrame.top != bt
                     || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
                 mBoltFrame.set(bl, bt, br, bb);
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 112780b..e6fd7d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -38,9 +38,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;
@@ -63,6 +62,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;
@@ -94,9 +94,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;
@@ -120,13 +118,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);
@@ -173,7 +169,6 @@
         mLocationController = locationController;
 
         setupQuickSettings();
-        updateWifiDisplayStatus();
         updateResources();
         applyLocationEnabledStatus();
 
@@ -316,11 +311,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,
@@ -699,20 +702,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
@@ -847,15 +863,6 @@
         dialog.show();
     }
 
-    private void updateWifiDisplayStatus() {
-        mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
-        applyWifiDisplayStatus();
-    }
-
-    private void applyWifiDisplayStatus() {
-        mModel.onWifiDisplayStateChanged(mWifiDisplayStatus);
-    }
-
     private void applyBluetoothStatus() {
         mModel.onBluetoothStateChange(mBluetoothState);
     }
@@ -879,12 +886,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 fa97a11..7ba3968 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.net.Uri;
 import android.os.Handler;
@@ -58,7 +59,6 @@
         BrightnessStateChangeCallback,
         RotationLockControllerCallback,
         LocationSettingsChangeCallback {
-
     // Sett InputMethoManagerService
     private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
 
@@ -294,6 +294,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;
@@ -304,6 +328,9 @@
     private final DisplayContrastObserver mContrastObserver;
     private final DisplayColorSpaceObserver mColorSpaceObserver;
 
+    private final MediaRouter mMediaRouter;
+    private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
+
     private final boolean mHasMobileData;
 
     private QuickSettingsTileView mUserTile;
@@ -326,9 +353,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;
@@ -401,6 +428,7 @@
                 onColorSpaceChanged();
                 onNextAlarmChanged();
                 onBugreportChanged();
+                rebindMediaRouterAsCurrentUser();
             }
         };
 
@@ -417,6 +445,11 @@
         mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler);
         mColorSpaceObserver.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);
@@ -744,24 +777,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/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index e77b420..4901823 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -113,7 +113,7 @@
             handled = super.onTouchEvent(ev);
         }
         final int action = ev.getAction();
-        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+        if (!handled && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) {
             mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
         }
         return handled;
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/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
index e14f89a..8511de2 100644
--- a/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
+++ b/packages/WallpaperCropper/src/com/android/photos/BitmapRegionTileSource.java
@@ -24,6 +24,9 @@
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapRegionDecoder;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
@@ -53,7 +56,8 @@
     private SimpleBitmapRegionDecoderWrapper(BitmapRegionDecoder decoder) {
         mDecoder = decoder;
     }
-    public static SimpleBitmapRegionDecoderWrapper newInstance(String pathName, boolean isShareable) {
+    public static SimpleBitmapRegionDecoderWrapper newInstance(
+            String pathName, boolean isShareable) {
         try {
             BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(pathName, isShareable);
             if (d != null) {
@@ -65,7 +69,8 @@
         }
         return null;
     }
-    public static SimpleBitmapRegionDecoderWrapper newInstance(InputStream is, boolean isShareable) {
+    public static SimpleBitmapRegionDecoderWrapper newInstance(
+            InputStream is, boolean isShareable) {
         try {
             BitmapRegionDecoder d = BitmapRegionDecoder.newInstance(is, isShareable);
             if (d != null) {
@@ -89,8 +94,9 @@
 }
 
 class DumbBitmapRegionDecoder implements SimpleBitmapRegionDecoder {
-    //byte[] streamCopy;
     Bitmap mBuffer;
+    Canvas mTempCanvas;
+    Paint mTempPaint;
     private DumbBitmapRegionDecoder(Bitmap b) {
         mBuffer = b;
     }
@@ -115,9 +121,23 @@
         return mBuffer.getHeight();
     }
     public Bitmap decodeRegion(Rect wantRegion, BitmapFactory.Options options) {
-        System.out.println("DECODING WITH SAMPLE LEVEL OF " + options.inSampleSize);
-        return Bitmap.createBitmap(
-                mBuffer, wantRegion.left, wantRegion.top, wantRegion.width(), wantRegion.height());
+        if (mTempCanvas == null) {
+            mTempCanvas = new Canvas();
+            mTempPaint = new Paint();
+            mTempPaint.setFilterBitmap(true);
+        }
+        int sampleSize = Math.max(options.inSampleSize, 1);
+        Bitmap newBitmap = Bitmap.createBitmap(
+                wantRegion.width() / sampleSize,
+                wantRegion.height() / sampleSize,
+                Bitmap.Config.ARGB_8888);
+        mTempCanvas.setBitmap(newBitmap);
+        mTempCanvas.save();
+        mTempCanvas.scale(1f / sampleSize, 1f / sampleSize);
+        mTempCanvas.drawBitmap(mBuffer, -wantRegion.left, -wantRegion.top, mTempPaint);
+        mTempCanvas.restore();
+        mTempCanvas.setBitmap(null);
+        return newBitmap;
     }
 }
 
@@ -256,6 +276,7 @@
                 if (regionDecoder == null) {
                     is = regenerateInputStream();
                     regionDecoder = DumbBitmapRegionDecoder.newInstance(is);
+                    Utils.closeSilently(is);
                 }
                 return regionDecoder;
             } catch (FileNotFoundException e) {
@@ -280,8 +301,9 @@
         }
         @Override
         public boolean readExif(ExifInterface ei) {
+            InputStream is = null;
             try {
-                InputStream is = regenerateInputStream();
+                is = regenerateInputStream();
                 ei.readExif(is);
                 Utils.closeSilently(is);
                 return true;
@@ -291,6 +313,8 @@
             } catch (IOException e) {
                 Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
                 return false;
+            } finally {
+                Utils.closeSilently(is);
             }
         }
     }
@@ -316,6 +340,7 @@
             if (regionDecoder == null) {
                 is = regenerateInputStream();
                 regionDecoder = DumbBitmapRegionDecoder.newInstance(is);
+                Utils.closeSilently(is);
             }
             return regionDecoder;
         }
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index d12140d..57c0581 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -247,19 +247,19 @@
     private static int getRotationFromExifHelper(
             String path, Resources res, int resId, Context context, Uri uri) {
         ExifInterface ei = new ExifInterface();
+        InputStream is = null;
+        BufferedInputStream bis = null;
         try {
             if (path != null) {
                 ei.readExif(path);
             } else if (uri != null) {
-                InputStream is = context.getContentResolver().openInputStream(uri);
-                BufferedInputStream bis = new BufferedInputStream(is);
+                is = context.getContentResolver().openInputStream(uri);
+                bis = new BufferedInputStream(is);
                 ei.readExif(bis);
-                bis.close();
             } else {
-                InputStream is = res.openRawResource(resId);
-                BufferedInputStream bis = new BufferedInputStream(is);
+                is = res.openRawResource(resId);
+                bis = new BufferedInputStream(is);
                 ei.readExif(bis);
-                bis.close();
             }
             Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
             if (ori != null) {
@@ -267,6 +267,9 @@
             }
         } catch (IOException e) {
             Log.w(LOGTAG, "Getting exif data failed", e);
+        } finally {
+            Utils.closeSilently(bis);
+            Utils.closeSilently(is);
         }
         return 0;
     }
@@ -326,40 +329,15 @@
         // Get the crop
         boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
 
-        Point minDims = new Point();
-        Point maxDims = new Point();
+
         Display d = getWindowManager().getDefaultDisplay();
-        d.getCurrentSizeRange(minDims, maxDims);
 
         Point displaySize = new Point();
         d.getSize(displaySize);
-
-        int maxDim = Math.max(maxDims.x, maxDims.y);
-        final int minDim = Math.min(minDims.x, minDims.y);
-        int defaultWallpaperWidth;
-        if (isScreenLarge(getResources())) {
-            defaultWallpaperWidth = (int) (maxDim *
-                    wallpaperTravelToScreenWidthRatio(maxDim, minDim));
-        } else {
-            defaultWallpaperWidth = Math.max((int)
-                    (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
-        }
-
         boolean isPortrait = displaySize.x < displaySize.y;
-        int portraitHeight;
-        if (isPortrait) {
-            portraitHeight = mCropView.getHeight();
-        } else {
-            // TODO: how to actually get the proper portrait height?
-            // This is not quite right:
-            portraitHeight = Math.max(maxDims.x, maxDims.y);
-        }
-        if (android.os.Build.VERSION.SDK_INT >=
-                android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            Point realSize = new Point();
-            d.getRealSize(realSize);
-            portraitHeight = Math.max(realSize.x, realSize.y);
-        }
+
+        Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
+                getWindowManager());
         // Get the crop
         RectF cropRect = mCropView.getCrop();
         int cropRotation = mCropView.getImageRotation();
@@ -378,7 +356,7 @@
         // (or all the way to the left, in RTL)
         float extraSpace = ltr ? rotatedInSize[0] - cropRect.right : cropRect.left;
         // Cap the amount of extra width
-        float maxExtraSpace = defaultWallpaperWidth / cropScale - cropRect.width();
+        float maxExtraSpace = defaultWallpaperSize.x / cropScale - cropRect.width();
         extraSpace = Math.min(extraSpace, maxExtraSpace);
 
         if (ltr) {
@@ -389,10 +367,10 @@
 
         // ADJUST CROP HEIGHT
         if (isPortrait) {
-            cropRect.bottom = cropRect.top + portraitHeight / cropScale;
+            cropRect.bottom = cropRect.top + defaultWallpaperSize.y / cropScale;
         } else { // LANDSCAPE
             float extraPortraitHeight =
-                    portraitHeight / cropScale - cropRect.height();
+                    defaultWallpaperSize.y / cropScale - cropRect.height();
             float expandHeight =
                     Math.min(Math.min(rotatedInSize[1] - cropRect.bottom, cropRect.top),
                             extraPortraitHeight / 2);
@@ -606,13 +584,13 @@
                 }
 
                 // See how much we're reducing the size of the image
-                int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth,
-                        roundedTrueCrop.height() / mOutHeight);
-
+                int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth,
+                        roundedTrueCrop.height() / mOutHeight));
                 // Attempt to open a region decoder
                 BitmapRegionDecoder decoder = null;
+                InputStream is = null;
                 try {
-                    InputStream is = regenerateInputStream();
+                    is = regenerateInputStream();
                     if (is == null) {
                         Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
                         failure = true;
@@ -622,6 +600,9 @@
                     Utils.closeSilently(is);
                 } catch (IOException e) {
                     Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
+                } finally {
+                   Utils.closeSilently(is);
+                   is = null;
                 }
 
                 Bitmap crop = null;
@@ -637,7 +618,7 @@
 
                 if (crop == null) {
                     // BitmapRegionDecoder has failed, try to crop in-memory
-                    InputStream is = regenerateInputStream();
+                    is = regenerateInputStream();
                     Bitmap fullSize = null;
                     if (is != null) {
                         BitmapFactory.Options options = new BitmapFactory.Options();
@@ -757,7 +738,7 @@
 
     protected void updateWallpaperDimensions(int width, int height) {
         String spKey = getSharedPreferencesKey();
-        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE);
+        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
         SharedPreferences.Editor editor = sp.edit();
         if (width != 0 && height != 0) {
             editor.putInt(WALLPAPER_WIDTH_KEY, width);
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index 8d97fc8..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;
     }
@@ -129,8 +130,8 @@
         final boolean wasAnim = mWin.isAnimatingLw();
         final boolean change = show ? mWin.showLw(true) : mWin.hideLw(true);
         final int state = computeStateLw(wasVis, wasAnim, mWin, change);
-        updateStateLw(state);
-        return change;
+        final boolean stateChanged = updateStateLw(state);
+        return change || stateChanged;
     }
 
     private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) {
@@ -139,6 +140,8 @@
             final boolean anim = win.isAnimatingLw();
             if (mState == StatusBarManager.WINDOW_STATE_HIDING && !change && !vis) {
                 return StatusBarManager.WINDOW_STATE_HIDDEN;
+            } else if (mState == StatusBarManager.WINDOW_STATE_HIDDEN && vis) {
+                return StatusBarManager.WINDOW_STATE_SHOWING;
             } else if (change) {
                 if (wasVis && vis && !wasAnim && anim) {
                     return StatusBarManager.WINDOW_STATE_HIDING;
@@ -150,7 +153,7 @@
         return mState;
     }
 
-    private void updateStateLw(final int state) {
+    private boolean updateStateLw(final int state) {
         if (state != mState) {
             mState = state;
             if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
@@ -169,7 +172,9 @@
                     }
                 }
             });
+            return true;
         }
+        return false;
     }
 
     public boolean checkHiddenLw() {
@@ -194,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;
@@ -207,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
             }
@@ -250,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/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 44fc1f8..93f0c1c 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -22,6 +22,10 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.*;
 
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
 import android.view.ViewConfiguration;
 
 import com.android.internal.R;
@@ -146,6 +150,8 @@
     private ActionMenuPresenterCallback mActionMenuPresenterCallback;
     private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
 
+    private TransitionManager mTransitionManager;
+
     // The icon resource has been explicitly set elsewhere
     // and should not be overwritten with a default.
     static final int FLAG_RESOURCE_SET_ICON = 1 << 0;
@@ -282,12 +288,22 @@
 
     @Override
     public void setContentView(int layoutResID) {
+        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
+        // decor, when theme attributes and the like are crystalized. Do not check the feature
+        // before this happens.
         if (mContentParent == null) {
             installDecor();
-        } else {
+        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
             mContentParent.removeAllViews();
         }
-        mLayoutInflater.inflate(layoutResID, mContentParent);
+
+        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
+                    getContext());
+            mTransitionManager.transitionTo(newScene);
+        } else {
+            mLayoutInflater.inflate(layoutResID, mContentParent);
+        }
         final Callback cb = getCallback();
         if (cb != null && !isDestroyed()) {
             cb.onContentChanged();
@@ -301,12 +317,22 @@
 
     @Override
     public void setContentView(View view, ViewGroup.LayoutParams params) {
+        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
+        // decor, when theme attributes and the like are crystalized. Do not check the feature
+        // before this happens.
         if (mContentParent == null) {
             installDecor();
-        } else {
+        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
             mContentParent.removeAllViews();
         }
-        mContentParent.addView(view, params);
+
+        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            view.setLayoutParams(params);
+            final Scene newScene = new Scene(mContentParent, view);
+            mTransitionManager.transitionTo(newScene);
+        } else {
+            mContentParent.addView(view, params);
+        }
         final Callback cb = getCallback();
         if (cb != null && !isDestroyed()) {
             cb.onContentChanged();
@@ -318,6 +344,11 @@
         if (mContentParent == null) {
             installDecor();
         }
+        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
+            // TODO Augment the scenes/transitions API to support this.
+            throw new UnsupportedOperationException(
+                    "addContentView does not support content transitions");
+        }
         mContentParent.addView(view, params);
         final Callback cb = getCallback();
         if (cb != null && !isDestroyed()) {
@@ -366,6 +397,7 @@
     }
 
     @Override
+    @Deprecated
     public void setTitleColor(int textColor) {
         if (mTitleView != null) {
             mTitleView.setTextColor(textColor);
@@ -2890,6 +2922,9 @@
             a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor,
                     mFixedHeightMinor);
         }
+        if (a.getBoolean(com.android.internal.R.styleable.Window_windowContentTransitions, false)) {
+            requestFeature(FEATURE_CONTENT_TRANSITIONS);
+        }
 
         final Context context = getContext();
         final int targetSdk = context.getApplicationInfo().targetSdkVersion;
@@ -3179,6 +3214,20 @@
                     });
                 }
             }
+
+            // Only inflate or create a new TransitionManager if the caller hasn't
+            // already set a custom one.
+            if (hasFeature(FEATURE_CONTENT_TRANSITIONS) && mTransitionManager == null) {
+                final int transitionRes = getWindowStyle().getResourceId(
+                        com.android.internal.R.styleable.Window_windowContentTransitionManager, 0);
+                if (transitionRes != 0) {
+                    final TransitionInflater inflater = TransitionInflater.from(getContext());
+                    mTransitionManager = inflater.inflateTransitionManager(transitionRes,
+                            mContentParent);
+                } else {
+                    mTransitionManager = new TransitionManager();
+                }
+            }
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index d653920..4d84984 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -234,7 +234,6 @@
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
 
-    boolean mHeadless;
     boolean mSafeMode;
     WindowState mStatusBar = null;
     int mStatusBarHeight;
@@ -308,17 +307,6 @@
     WindowState mFocusedWindow;
     IApplicationToken mFocusedApp;
 
-    private final class PointerLocationPointerEventListener implements PointerEventListener {
-        @Override
-        public void onPointerEvent(MotionEvent motionEvent) {
-            if (mPointerLocationView != null) {
-                mPointerLocationView.addPointerEvent(motionEvent);
-            }
-        }
-    }
-
-    // Pointer location view state, only modified on the mHandler Looper.
-    PointerLocationPointerEventListener mPointerLocationPointerEventListener;
     PointerLocationView mPointerLocationView;
 
     // The current size of the screen; really; extends into the overscan area of
@@ -858,7 +846,6 @@
         mContext = context;
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
-        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
         mHandler = new PolicyHandler();
         mOrientationListener = new MyOrientationListener(mContext, mHandler);
         try {
@@ -1190,7 +1177,6 @@
         if (mPointerLocationView == null) {
             mPointerLocationView = new PointerLocationView(mContext);
             mPointerLocationView.setPrintCoords(false);
-
             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                     WindowManager.LayoutParams.MATCH_PARENT,
                     WindowManager.LayoutParams.MATCH_PARENT);
@@ -1210,22 +1196,14 @@
                     mContext.getSystemService(Context.WINDOW_SERVICE);
             lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
             wm.addView(mPointerLocationView, lp);
-
-            mPointerLocationPointerEventListener = new PointerLocationPointerEventListener();
-            mWindowManagerFuncs.registerPointerEventListener(mPointerLocationPointerEventListener);
+            mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView);
         }
     }
 
     private void disablePointerLocation() {
-        if (mPointerLocationPointerEventListener != null) {
-            mWindowManagerFuncs.unregisterPointerEventListener(
-                    mPointerLocationPointerEventListener);
-            mPointerLocationPointerEventListener = null;
-        }
-
         if (mPointerLocationView != null) {
-            WindowManager wm = (WindowManager)
-                    mContext.getSystemService(Context.WINDOW_SERVICE);
+            mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView);
+            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
             wm.removeView(mPointerLocationView);
             mPointerLocationView = null;
         }
@@ -3473,6 +3451,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()
@@ -3602,9 +3585,6 @@
 
     /** {@inheritDoc} */
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-        // do nothing if headless
-        if (mHeadless) return;
-
         // lid changed state
         final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
         if (newLidState == mLidState) {
@@ -3837,7 +3817,7 @@
         //        the device some other way (which is why we have an exemption here for injected
         //        events).
         int result;
-        if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
+        if (isScreenOn || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
         } else {
@@ -4663,10 +4643,9 @@
     /** {@inheritDoc} */
     @Override
     public void systemReady() {
-        if (!mHeadless) {
-            mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
-            mKeyguardDelegate.onSystemReady();
-        }
+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
+        mKeyguardDelegate.onSystemReady();
+
         synchronized (mLock) {
             updateOrientationListenerLp();
             mSystemReady = true;
@@ -4693,7 +4672,6 @@
 
     /** {@inheritDoc} */
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        if (mHeadless) return;
         mHandler.post(new Runnable() {
             @Override public void run() {
                 if (mBootMsgDialog == null) {
@@ -5166,9 +5144,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/input/EventHub.cpp b/services/input/EventHub.cpp
index e67c64c..09fca040 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -1275,6 +1275,12 @@
 
     String8 wakeMechanism("EPOLLWAKEUP");
     if (!mUsingEpollWakeup) {
+#ifndef EVIOCSSUSPENDBLOCK
+        // uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels
+        // will use an epoll flag instead, so as long as we want to support
+        // this feature, we need to be prepared to define the ioctl ourselves.
+#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
+#endif
         if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) {
             wakeMechanism = "<none>";
         } else {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 571724d..4bdf992 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1568,9 +1568,12 @@
             return false;
         }
         NetworkStateTracker tracker = mNetTrackers[networkType];
-        DetailedState netState = tracker.getNetworkInfo().getDetailedState();
+        DetailedState netState = DetailedState.DISCONNECTED;
+        if (tracker != null) {
+            netState = tracker.getNetworkInfo().getDetailedState();
+        }
 
-        if (tracker == null || (netState != DetailedState.CONNECTED &&
+        if ((netState != DetailedState.CONNECTED &&
                 netState != DetailedState.CAPTIVE_PORTAL_CHECK) ||
                 tracker.isTeardownRequested()) {
             if (VDBG) {
@@ -3348,6 +3351,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();
@@ -3391,6 +3399,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;
             }
@@ -3415,6 +3428,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/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 0e0f156..3a1c747 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -51,10 +51,15 @@
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.appwidget.AppWidgetService;
+import com.android.server.backup.BackupManagerService;
+import com.android.server.clipboard.ClipboardService;
 import com.android.server.content.ContentService;
+import com.android.server.devicepolicy.DevicePolicyManagerService;
 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;
@@ -66,6 +71,7 @@
 import com.android.server.print.PrintManagerService;
 import com.android.server.search.SearchManagerService;
 import com.android.server.usb.UsbService;
+import com.android.server.wallpaper.WallpaperManagerService;
 import com.android.server.wifi.WifiService;
 import com.android.server.wm.WindowManagerService;
 
@@ -121,7 +127,6 @@
         String factoryTestStr = SystemProperties.get("ro.factorytest");
         int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
                 : Integer.parseInt(factoryTestStr);
-        final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
 
         Installer installer = null;
         AccountManagerService accountManager = null;
@@ -356,6 +361,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) {
@@ -622,10 +628,8 @@
                         R.bool.config_enableWallpaperService)) {
                 try {
                     Slog.i(TAG, "Wallpaper Service");
-                    if (!headless) {
-                        wallpaper = new WallpaperManagerService(context);
-                        ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
-                    }
+                    wallpaper = new WallpaperManagerService(context);
+                    ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
                 } catch (Throwable e) {
                     reportWtf("starting Wallpaper Service", e);
                 }
@@ -804,6 +808,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 +930,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
@@ -931,8 +946,10 @@
                 } catch (Throwable e) {
                     reportWtf("observing native crashes", e);
                 }
-                if (!headless) {
+                try {
                     startSystemUi(contextF);
+                } catch (Throwable e) {
+                    reportWtf("starting System UI", e);
                 }
                 try {
                     if (mountServiceF != null) mountServiceF.systemReady();
@@ -1063,6 +1080,12 @@
                 } catch (Throwable e) {
                     reportWtf("Notifying PrintManagerService running", e);
                 }
+
+                try {
+                    if (mediaRouterF != null) mediaRouterF.systemRunning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying MediaRouterService running", e);
+                }
             }
         });
 
@@ -1104,6 +1127,19 @@
     private static native void nativeInit();
 
     public static void main(String[] args) {
+
+        /*
+         * In case the runtime switched since last boot (such as when
+         * the old runtime was removed in an OTA), set the system
+         * property so that it is in sync. We can't do this in
+         * libnativehelper's JniInvocation::Init code where we already
+         * had to fallback to a different runtime because it is
+         * running as root and we need to be the system user to set
+         * the property. http://b/11463182
+         */
+        SystemProperties.set("persist.sys.dalvik.vm.lib",
+                             VMRuntime.getRuntime().vmLibrary());
+
         if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
             // If a device's clock is before 1970 (before 0), a lot of
             // APIs crash dealing with negative numbers, notably
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 6186b9e..933247e 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -26,6 +26,7 @@
 
 import android.os.Handler;
 import android.os.Looper;
+import android.os.SystemProperties;
 import android.util.ArrayMap;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
@@ -76,7 +77,7 @@
 
     // How long a service needs to be running until restarting its process
     // is no longer considered to be a relaunch of the service.
-    static final int SERVICE_RESTART_DURATION = 5*1000;
+    static final int SERVICE_RESTART_DURATION = 1*1000;
 
     // How long a service needs to be running until it will start back at
     // SERVICE_RESTART_DURATION after being killed.
@@ -239,7 +240,12 @@
 
     public ActiveServices(ActivityManagerService service) {
         mAm = service;
-        mMaxStartingBackground = ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
+        int maxBg = 0;
+        try {
+            maxBg = Integer.parseInt(SystemProperties.get("ro.config.max_starting_bg", "0"));
+        } catch(RuntimeException e) {
+        }
+        mMaxStartingBackground = maxBg > 0 ? maxBg : ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
     }
 
     ServiceRecord getServiceByName(ComponentName name, int callingUser) {
@@ -301,7 +307,7 @@
         ServiceRecord r = res.record;
         NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                 callingUid, r.packageName, service, service.getFlags(), null);
-        if (unscheduleServiceRestartLocked(r)) {
+        if (unscheduleServiceRestartLocked(r, callingUid, false)) {
             if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
         }
         r.lastActivity = SystemClock.uptimeMillis();
@@ -695,7 +701,7 @@
         final long origId = Binder.clearCallingIdentity();
 
         try {
-            if (unscheduleServiceRestartLocked(s)) {
+            if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
                 if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
                         + s);
             }
@@ -996,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--;
                         }
                     }
                 }
@@ -1095,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
@@ -1141,16 +1152,9 @@
                     r.restartCount = 1;
                     r.restartDelay = minDuration;
                 } else {
-                    if ((r.serviceInfo.applicationInfo.flags
-                            &ApplicationInfo.FLAG_PERSISTENT) != 0) {
-                        // Services in peristent processes will restart much more
-                        // quickly, since they are pretty important.  (Think SystemUI).
-                        r.restartDelay += minDuration/2;
-                    } else {
-                        r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
-                        if (r.restartDelay < minDuration) {
-                            r.restartDelay = minDuration;
-                        }
+                    r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
+                    if (r.restartDelay < minDuration) {
+                        r.restartDelay = minDuration;
                     }
                 }
             }
@@ -1177,7 +1181,7 @@
             } while (repeat);
 
         } else {
-            // Persistent processes are immediately restrted, so there is no
+            // Persistent processes are immediately restarted, so there is no
             // reason to hold of on restarting their services.
             r.totalRestartCount++;
             r.restartCount = 0;
@@ -1188,6 +1192,7 @@
         if (!mRestartingServices.contains(r)) {
             r.createdFromFg = false;
             mRestartingServices.add(r);
+            r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
         }
 
         r.cancelNotification();
@@ -1210,16 +1215,44 @@
         bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true);
     }
 
-    private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
-        if (r.restartDelay == 0) {
+    private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid,
+            boolean force) {
+        if (!force && r.restartDelay == 0) {
             return false;
         }
-        r.resetRestartCounter();
-        mRestartingServices.remove(r);
+        // Remove from the restarting list; if the service is currently on the
+        // restarting list, or the call is coming from another app, then this
+        // service has become of much more interest so we reset the restart interval.
+        boolean removed = mRestartingServices.remove(r);
+        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:");
@@ -1239,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) {
@@ -1379,6 +1414,7 @@
         } finally {
             if (!created) {
                 app.services.remove(r);
+                r.app = null;
                 scheduleServiceRestartLocked(r, false);
             }
         }
@@ -1549,16 +1585,13 @@
         smap.mServicesByName.remove(r.name);
         smap.mServicesByIntent.remove(r.intent);
         r.totalRestartCount = 0;
-        unscheduleServiceRestartLocked(r);
+        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--;
             }
         }
 
@@ -1577,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);
@@ -1587,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);
@@ -1765,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);
     }
@@ -1812,6 +1846,12 @@
                     r.tracker = null;
                 }
             }
+            if (finishing) {
+                if (r.app != null) {
+                    r.app.services.remove(r);
+                }
+                r.app = null;
+            }
         }
     }
 
@@ -1890,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;
@@ -1956,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
@@ -1986,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;
@@ -2016,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);
@@ -2050,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 b521ee7..f9ffc36 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -331,8 +331,6 @@
 
     public IntentFirewall mIntentFirewall;
 
-    private final boolean mHeadless;
-
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
     // default actuion automatically.  Important for devices without direct input
     // devices.
@@ -457,6 +455,23 @@
     final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
 
     /**
+     * Information about a process that is currently marked as bad.
+     */
+    static final class BadProcessInfo {
+        BadProcessInfo(long time, String shortMsg, String longMsg, String stack) {
+            this.time = time;
+            this.shortMsg = shortMsg;
+            this.longMsg = longMsg;
+            this.stack = stack;
+        }
+
+        final long time;
+        final String shortMsg;
+        final String longMsg;
+        final String stack;
+    }
+
+    /**
      * Set of applications that we consider to be bad, and will reject
      * incoming broadcasts from (which the user has no control over).
      * Processes are added to this set when they have crashed twice within
@@ -464,7 +479,7 @@
      * later restarted (hopefully due to some user action).  The value is the
      * time it was added to the list.
      */
-    final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
+    final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<BadProcessInfo>();
 
     /**
      * All of the processes we currently have running organized by pid.
@@ -1967,8 +1982,6 @@
 
         mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
 
-        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
-
         // User 0 is the first and only user that runs at boot.
         mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
         mUserLru.add(Integer.valueOf(0));
@@ -2132,7 +2145,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);
@@ -2752,10 +2766,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();
                 }
             }
 
@@ -2835,13 +2849,6 @@
     }
 
     boolean startHomeActivityLocked(int userId) {
-        if (mHeadless) {
-            // Added because none of the other calls to ensureBootCompleted seem to fire
-            // when running headless.
-            ensureBootCompleted();
-            return false;
-        }
-
         if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
                 && mTopAction == null) {
             // We are running in factory test mode, but unable to find
@@ -4986,7 +4993,7 @@
         // See if the top visible activity is waiting to run in this process...
         if (normalMode) {
             try {
-                if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
+                if (mStackSupervisor.attachApplicationLocked(app)) {
                     didSomething = true;
                 }
             } catch (Exception e) {
@@ -8137,10 +8144,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) {
@@ -9422,7 +9426,7 @@
                 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
         startAppProblemLocked(app);
         app.stopFreezingAllLocked();
-        return handleAppCrashLocked(app);
+        return handleAppCrashLocked(app, shortMsg, longMsg, stackTrace);
     }
 
     private void makeAppNotRespondingLocked(ProcessRecord app,
@@ -9477,17 +9481,14 @@
                 app.waitDialog = null;
             }
             if (app.pid > 0 && app.pid != MY_PID) {
-                handleAppCrashLocked(app);
+                handleAppCrashLocked(app, null, null, null);
                 killUnneededProcessLocked(app, "user request after error");
             }
         }
     }
 
-    private boolean handleAppCrashLocked(ProcessRecord app) {
-        if (mHeadless) {
-            Log.e(TAG, "handleAppCrashLocked: " + app.processName);
-            return false;
-        }
+    private boolean handleAppCrashLocked(ProcessRecord app, String shortMsg, String longMsg,
+            String stackTrace) {
         long now = SystemClock.uptimeMillis();
 
         Long crashTime;
@@ -9513,7 +9514,8 @@
                 if (!app.isolated) {
                     // XXX We don't have a way to mark isolated processes
                     // as bad, since they don't have a peristent identity.
-                    mBadProcesses.put(app.info.processName, app.uid, now);
+                    mBadProcesses.put(app.info.processName, app.uid,
+                            new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
                     mProcessCrashTimes.remove(app.info.processName, app.uid);
                 }
                 app.bad = true;
@@ -10775,11 +10777,11 @@
 
         if (mBadProcesses.getMap().size() > 0) {
             boolean printed = false;
-            final ArrayMap<String, SparseArray<Long>> pmap = mBadProcesses.getMap();
+            final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
             final int NP = pmap.size();
             for (int ip=0; ip<NP; ip++) {
                 String pname = pmap.keyAt(ip);
-                SparseArray<Long> uids = pmap.valueAt(ip);
+                SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
                 final int N = uids.size();
                 for (int i=0; i<N; i++) {
                     int puid = uids.keyAt(i);
@@ -10794,10 +10796,33 @@
                         pw.println("  Bad processes:");
                         printedAnything = true;
                     }
+                    BadProcessInfo info = uids.valueAt(i);
                     pw.print("    Bad process "); pw.print(pname);
                             pw.print(" uid "); pw.print(puid);
-                            pw.print(": crashed at time ");
-                            pw.println(uids.valueAt(i));
+                            pw.print(": crashed at time "); pw.println(info.time);
+                    if (info.shortMsg != null) {
+                        pw.print("      Short msg: "); pw.println(info.shortMsg);
+                    }
+                    if (info.longMsg != null) {
+                        pw.print("      Long msg: "); pw.println(info.longMsg);
+                    }
+                    if (info.stack != null) {
+                        pw.println("      Stack:");
+                        int lastPos = 0;
+                        for (int pos=0; pos<info.stack.length(); pos++) {
+                            if (info.stack.charAt(pos) == '\n') {
+                                pw.print("        ");
+                                pw.write(info.stack, lastPos, pos-lastPos);
+                                pw.println();
+                                lastPos = pos+1;
+                            }
+                        }
+                        if (lastPos < info.stack.length()) {
+                            pw.print("        ");
+                            pw.write(info.stack, lastPos, info.stack.length()-lastPos);
+                            pw.println();
+                        }
+                    }
                 }
             }
         }
@@ -11863,6 +11888,7 @@
         boolean dumpDalvik = false;
         boolean oomOnly = false;
         boolean isCompact = false;
+        boolean localOnly = false;
         
         int opti = 0;
         while (opti < args.length) {
@@ -11881,12 +11907,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;
@@ -12003,14 +12032,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();
+                            }
                         }
                     }
                 }
@@ -13995,9 +14032,6 @@
      */
     boolean updateConfigurationLocked(Configuration values,
             ActivityRecord starting, boolean persistent, boolean initLocale) {
-        // do nothing if we are headless
-        if (mHeadless) return true;
-
         int changes = 0;
 
         if (values != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 2312d41ef..cd2cb331 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;
@@ -546,7 +547,7 @@
 
         // Move userId's tasks to the top.
         int index = mTaskHistory.size();
-        for (int i = 0; i < index; ++i) {
+        for (int i = 0; i < index; ) {
             TaskRecord task = mTaskHistory.get(i);
             if (task.userId == userId) {
                 if (DEBUG_TASKS) Slog.d(TAG, "switchUserLocked: stack=" + getStackId() +
@@ -554,6 +555,9 @@
                 mTaskHistory.remove(i);
                 mTaskHistory.add(task);
                 --index;
+                // Use same value for i.
+            } else {
+                ++i;
             }
         }
         if (VALIDATE_TOKENS) {
@@ -977,8 +981,8 @@
                 if (r.isHomeActivity()) {
                     return true;
                 }
-                if (!r.finishing && r.visible && r.fullscreen) {
-                    // Passed activity is over a visible fullscreen activity.
+                if (!r.finishing && r.fullscreen) {
+                    // Passed activity is over a fullscreen activity.
                     return false;
                 }
             }
@@ -1121,7 +1125,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(
@@ -1722,7 +1726,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();
                         }
@@ -1783,7 +1787,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
@@ -1827,7 +1832,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) {
@@ -1917,26 +1923,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);
 
@@ -1957,8 +1975,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);
@@ -3152,7 +3170,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..f4ca324 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -366,7 +366,7 @@
         return resumedActivity;
     }
 
-    boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
+    boolean attachApplicationLocked(ProcessRecord app) throws Exception {
         boolean didSomething = false;
         final String processName = app.processName;
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -379,10 +379,7 @@
                 if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                         && processName.equals(hr.processName)) {
                     try {
-                        if (headless) {
-                            Slog.e(TAG, "Starting activities not supported on headless device: "
-                                    + hr);
-                        } else if (realStartActivityLocked(hr, app, true, true)) {
+                        if (realStartActivityLocked(hr, app, true, true)) {
                             didSomething = true;
                         }
                     } catch (Exception e) {
@@ -1386,17 +1383,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 +1670,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/AppWidgetService.java b/services/java/com/android/server/appwidget/AppWidgetService.java
similarity index 98%
rename from services/java/com/android/server/AppWidgetService.java
rename to services/java/com/android/server/appwidget/AppWidgetService.java
index 203cca6..6fd8871 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/appwidget/AppWidgetService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.appwidget;
 
 import android.app.ActivityManager;
 import android.appwidget.AppWidgetProviderInfo;
@@ -48,7 +48,7 @@
 /**
  * Redirects calls to this service to the instance of the service for the appropriate user.
  */
-class AppWidgetService extends IAppWidgetService.Stub
+public class AppWidgetService extends IAppWidgetService.Stub
 {
     private static final String TAG = "AppWidgetService";
 
@@ -60,7 +60,7 @@
 
     private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
 
-    AppWidgetService(Context context) {
+    public AppWidgetService(Context context) {
         mContext = context;
 
         mSaveStateHandler = BackgroundThread.getHandler();
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/appwidget/AppWidgetServiceImpl.java
similarity index 99%
rename from services/java/com/android/server/AppWidgetServiceImpl.java
rename to services/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 69ae846..98dead3 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.appwidget;
 
 import android.app.AlarmManager;
 import android.app.AppGlobals;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/backup/BackupManagerService.java
similarity index 98%
rename from services/java/com/android/server/BackupManagerService.java
rename to services/java/com/android/server/backup/BackupManagerService.java
index 455d5e9..4bc29b8 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/backup/BackupManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
@@ -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;
@@ -81,7 +83,8 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.backup.IObbBackupService;
 import com.android.internal.backup.LocalTransport;
-import com.android.server.PackageManagerBackupAgent.Metadata;
+import com.android.server.EventLogTags;
+import com.android.server.backup.PackageManagerBackupAgent.Metadata;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -133,7 +136,7 @@
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
-class BackupManagerService extends IBackupManager.Stub {
+public class BackupManagerService extends IBackupManager.Stub {
     private static final String TAG = "BackupManagerService";
     private static final boolean DEBUG = true;
     private static final boolean MORE_DEBUG = false;
@@ -146,6 +149,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 +255,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 +822,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 +830,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
@@ -1111,7 +1127,8 @@
         // First, on an encrypted device we require matching the device pw
         final boolean isEncrypted;
         try {
-            isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+            isEncrypted = (mMountService.getEncryptionState() !=
+                    IMountService.ENCRYPTION_STATE_NONE);
             if (isEncrypted) {
                 if (DEBUG) {
                     Slog.i(TAG, "Device encrypted; verifying against device data pw");
@@ -1298,13 +1315,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 +1410,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);
         }
     };
 
@@ -5337,7 +5362,8 @@
 
                         boolean isEncrypted;
                         try {
-                            isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+                            isEncrypted = (mMountService.getEncryptionState() !=
+                                    IMountService.ENCRYPTION_STATE_NONE);
                             if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
                         } catch (RemoteException e) {
                             // couldn't contact the mount service; fail "safe" and assume encryption
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/backup/PackageManagerBackupAgent.java
similarity index 99%
rename from services/java/com/android/server/PackageManagerBackupAgent.java
rename to services/java/com/android/server/backup/PackageManagerBackupAgent.java
index 77bddb0..495da88 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/backup/SystemBackupAgent.java
similarity index 79%
rename from services/java/com/android/server/SystemBackupAgent.java
rename to services/java/com/android/server/backup/SystemBackupAgent.java
index 8cf273d..26e2e2a 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/backup/SystemBackupAgent.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 
+import android.app.IWallpaperManager;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupAgentHelper;
@@ -26,11 +27,11 @@
 import android.content.Context;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.Slog;
 
-
 import java.io.File;
 import java.io.IOException;
 
@@ -63,16 +64,23 @@
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
         // We only back up the data under the current "wallpaper" schema with metadata
-        WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+        IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
                 Context.WALLPAPER_SERVICE);
         String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
         String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
-        if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
-            // When the wallpaper has a name, back up the info by itself.
-            // TODO: Don't rely on the innards of the service object like this!
-            // TODO: Send a delete for any stored wallpaper image in this case?
-            files = new String[] { WALLPAPER_INFO };
-            keys = new String[] { WALLPAPER_INFO_KEY };
+        if (wallpaper != null) {
+            try {
+                final String wallpaperName = wallpaper.getName();
+                if (wallpaperName != null && wallpaperName.length() > 0) {
+                    // When the wallpaper has a name, back up the info by itself.
+                    // TODO: Don't rely on the innards of the service object like this!
+                    // TODO: Send a delete for any stored wallpaper image in this case?
+                    files = new String[] { WALLPAPER_INFO };
+                    keys = new String[] { WALLPAPER_INFO_KEY };
+                }
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
+            }
         }
         addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
         super.onBackup(oldState, data, newState);
@@ -109,9 +117,15 @@
         try {
             super.onRestore(data, appVersionCode, newState);
 
-            WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+            IWallpaperManager wallpaper = (IWallpaperManager) ServiceManager.getService(
                     Context.WALLPAPER_SERVICE);
-            wallpaper.settingsRestored();
+            if (wallpaper != null) {
+                try {
+                    wallpaper.settingsRestored();
+                } catch (RemoteException re) {
+                    Slog.e(TAG, "Couldn't restore settings\n" + re);
+                }
+            }
         } catch (IOException ex) {
             // If there was a failure, delete everything for the wallpaper, this is too aggressive,
             // but this is hopefully a rare failure.
@@ -149,10 +163,16 @@
             FullBackup.restoreFile(data, size, type, mode, mtime, outFile);
 
             if (restoredWallpaper) {
-                WallpaperManagerService wallpaper =
-                        (WallpaperManagerService)ServiceManager.getService(
+                IWallpaperManager wallpaper =
+                        (IWallpaperManager)ServiceManager.getService(
                         Context.WALLPAPER_SERVICE);
-                wallpaper.settingsRestored();
+                if (wallpaper != null) {
+                    try {
+                        wallpaper.settingsRestored();
+                    } catch (RemoteException re) {
+                        Slog.e(TAG, "Couldn't restore settings\n" + re);
+                    }
+                }
             }
         } catch (IOException e) {
             if (restoredWallpaper) {
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/clipboard/ClipboardService.java
similarity index 99%
rename from services/java/com/android/server/ClipboardService.java
rename to services/java/com/android/server/clipboard/ClipboardService.java
index 069ae23..6aa596d 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/clipboard/ClipboardService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.clipboard;
 
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index 11c3fa0..deb2377 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -764,7 +764,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 e99adc5..10f0ea7 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -1422,21 +1422,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/DevicePolicyManagerService.java b/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
similarity index 99%
rename from services/java/com/android/server/DevicePolicyManagerService.java
rename to services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8cc80f7..53b8dc4 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.devicepolicy;
 
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 
@@ -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/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 249c8b0..85681c3 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -101,7 +101,6 @@
     // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
     private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
 
-    private static final String SYSTEM_HEADLESS = "ro.config.headless";
     private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
 
     private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
@@ -115,7 +114,6 @@
     private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
 
     private final Context mContext;
-    private final boolean mHeadless;
     private final DisplayManagerHandler mHandler;
     private final Handler mUiHandler;
     private final DisplayAdapterListener mDisplayAdapterListener;
@@ -198,8 +196,6 @@
 
     public DisplayManagerService(Context context, Handler mainHandler) {
         mContext = context;
-        mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
-
         mHandler = new DisplayManagerHandler(mainHandler.getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayAdapterListener = new DisplayAdapterListener();
@@ -266,15 +262,6 @@
     }
 
     /**
-     * Returns true if the device is headless.
-     *
-     * @return True if the device is headless.
-     */
-    public boolean isHeadless() {
-        return mHeadless;
-    }
-
-    /**
      * Registers a display transaction listener to provide the client a chance to
      * update its surfaces within the same transaction as any display layout updates.
      *
@@ -466,6 +453,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 +473,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 +490,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 +507,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 +524,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 +546,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 +566,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 +583,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 +599,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) {
@@ -728,13 +710,8 @@
     private void registerDefaultDisplayAdapter() {
         // Register default display adapter.
         synchronized (mSyncRoot) {
-            if (mHeadless) {
-                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
-                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
-            } else {
-                registerDisplayAdapterLocked(new LocalDisplayAdapter(
-                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
-            }
+            registerDisplayAdapterLocked(new LocalDisplayAdapter(
+                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
         }
     }
 
@@ -1102,7 +1079,6 @@
         pw.println("DISPLAY MANAGER (dumpsys display)");
 
         synchronized (mSyncRoot) {
-            pw.println("  mHeadless=" + mHeadless);
             pw.println("  mOnlyCode=" + mOnlyCore);
             pw.println("  mSafeMode=" + mSafeMode);
             pw.println("  mPendingTraversal=" + mPendingTraversal);
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
deleted file mode 100644
index 7a104d7..0000000
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ /dev/null
@@ -1,73 +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.server.display;
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.DisplayMetrics;
-import android.view.Display;
-
-/**
- * Provides a fake default display for headless systems.
- * <p>
- * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
- * </p>
- */
-final class HeadlessDisplayAdapter extends DisplayAdapter {
-    private static final String TAG = "HeadlessDisplayAdapter";
-
-    // Called with SyncRoot lock held.
-    public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
-            Context context, Handler handler, Listener listener) {
-        super(syncRoot, context, handler, listener, TAG);
-    }
-
-    @Override
-    public void registerLocked() {
-        super.registerLocked();
-        sendDisplayDeviceEventLocked(new HeadlessDisplayDevice(), DISPLAY_DEVICE_EVENT_ADDED);
-    }
-
-    private final class HeadlessDisplayDevice extends DisplayDevice {
-        private DisplayDeviceInfo mInfo;
-
-        public HeadlessDisplayDevice() {
-            super(HeadlessDisplayAdapter.this, null);
-        }
-
-        @Override
-        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
-            if (mInfo == null) {
-                mInfo = new DisplayDeviceInfo();
-                mInfo.name = getContext().getResources().getString(
-                        com.android.internal.R.string.display_manager_built_in_display_name);
-                mInfo.width = 640;
-                mInfo.height = 480;
-                mInfo.refreshRate = 60;
-                mInfo.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
-                mInfo.xDpi = 160;
-                mInfo.yDpi = 160;
-                mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
-                        | DisplayDeviceInfo.FLAG_SECURE
-                        | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
-                mInfo.type = Display.TYPE_BUILT_IN;
-                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
-            }
-            return mInfo;
-        }
-    }
-}
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/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 5d6adc2..271e9e9 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -464,21 +464,21 @@
             private NetworkStatsCollection mUidTagComplete;
 
             private NetworkStatsCollection getUidComplete() {
-                if (mUidComplete == null) {
-                    synchronized (mStatsLock) {
+                synchronized (mStatsLock) {
+                    if (mUidComplete == null) {
                         mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
                     }
+                    return mUidComplete;
                 }
-                return mUidComplete;
             }
 
             private NetworkStatsCollection getUidTagComplete() {
-                if (mUidTagComplete == null) {
-                    synchronized (mStatsLock) {
+                synchronized (mStatsLock) {
+                    if (mUidTagComplete == null) {
                         mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
                     }
+                    return mUidTagComplete;
                 }
-                return mUidTagComplete;
             }
 
             @Override
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index fdeeebd..5761f6c 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;
@@ -4959,6 +4978,18 @@
                         permissionMap.put(p.info.name, bp);
                     }
                     if (bp.perm == null) {
+                        if (bp.sourcePackage != null
+                                && !bp.sourcePackage.equals(p.info.packageName)) {
+                            // If this is a permission that was formerly defined by a non-system
+                            // app, but is now defined by a system app (following an upgrade),
+                            // discard the previous declaration and consider the system's to be
+                            // canonical.
+                            if (isSystemApp(p.owner)) {
+                                Slog.i(TAG, "New decl " + p.owner + " of permission  "
+                                        + p.info.name + " is system");
+                                bp.sourcePackage = null;
+                            }
+                        }
                         if (bp.sourcePackage == null
                                 || bp.sourcePackage.equals(p.info.packageName)) {
                             BasePermission tree = findPermissionTreeLP(p.info.name);
@@ -9999,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(
@@ -10020,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/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index f93ba2f..8916926 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -17,7 +17,6 @@
 package com.android.server.pm;
 
 import com.android.internal.util.XmlUtils;
-import com.android.server.PreferredComponent;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/java/com/android/server/PreferredComponent.java b/services/java/com/android/server/pm/PreferredComponent.java
similarity index 99%
rename from services/java/com/android/server/PreferredComponent.java
rename to services/java/com/android/server/pm/PreferredComponent.java
index a7af252..f437372 100644
--- a/services/java/com/android/server/PreferredComponent.java
+++ b/services/java/com/android/server/pm/PreferredComponent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.pm;
 
 import com.android.internal.util.XmlUtils;
 
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 94bac17..e599409 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1959,10 +1959,14 @@
         }
 
         boolean doNonData = true;
+        boolean hasSchemes = false;
 
         for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) {
             boolean doScheme = true;
             String scheme = tmpPa.getDataScheme(ischeme);
+            if (scheme != null && !scheme.isEmpty()) {
+                hasSchemes = true;
+            }
             for (int issp=0; issp<tmpPa.countDataSchemeSpecificParts(); issp++) {
                 Uri.Builder builder = new Uri.Builder();
                 builder.scheme(scheme);
@@ -2016,11 +2020,25 @@
         }
 
         for (int idata=0; idata<tmpPa.countDataTypes(); idata++) {
-            Intent finalIntent = new Intent(intent);
             String mimeType = tmpPa.getDataType(idata);
-            finalIntent.setType(mimeType);
-            applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
-                    null, null, null, null, mimeType, userId);
+            if (hasSchemes) {
+                Uri.Builder builder = new Uri.Builder();
+                for (int ischeme=0; ischeme<tmpPa.countDataSchemes(); ischeme++) {
+                    String scheme = tmpPa.getDataScheme(ischeme);
+                    if (scheme != null && !scheme.isEmpty()) {
+                        Intent finalIntent = new Intent(intent);
+                        builder.scheme(scheme);
+                        finalIntent.setDataAndType(builder.build(), mimeType);
+                        applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                                scheme, null, null, null, mimeType, userId);
+                    }
+                }
+            } else {
+                Intent finalIntent = new Intent(intent);
+                finalIntent.setType(mimeType);
+                applyDefaultPreferredActivityLPw(service, finalIntent, flags, cn,
+                        null, null, null, null, mimeType, userId);
+            }
             doNonData = false;
         }
 
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 976a328..60d44c7 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -298,6 +298,10 @@
     // True if mAmbientLux holds a valid value.
     private boolean mAmbientLuxValid;
 
+    // The ambient light level threshold at which to brighten or darken the screen.
+    private float mBrighteningLuxThreshold;
+    private float mDarkeningLuxThreshold;
+
     // The most recent light sample.
     private float mLastObservedLux;
 
@@ -945,12 +949,24 @@
         mLastObservedLuxTime = time;
     }
 
+    private void setAmbientLux(float lux) {
+        mAmbientLux = lux;
+        mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
+        mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
+    }
+
     private void updateAmbientLux(long time) {
         // If the light sensor was just turned on then immediately update our initial
         // estimate of the current ambient light level.
-        if (!mAmbientLuxValid
-                || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
-            mAmbientLux = mRecentShortTermAverageLux;
+        if (!mAmbientLuxValid) {
+            final long timeWhenSensorWarmedUp =
+                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
+            if (time < timeWhenSensorWarmedUp) {
+                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
+                        timeWhenSensorWarmedUp);
+                return;
+            }
+            setAmbientLux(mRecentShortTermAverageLux);
             mAmbientLuxValid = true;
             mDebounceLuxDirection = 0;
             mDebounceLuxTime = time;
@@ -961,98 +977,90 @@
                         + ", mAmbientLux=" + mAmbientLux);
             }
             updateAutoBrightness(true);
-            return;
-        }
-
-        // Determine whether the ambient environment appears to be brightening.
-        float brighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
-        if (mRecentShortTermAverageLux > brighteningLuxThreshold
-                && mRecentLongTermAverageLux > brighteningLuxThreshold) {
+        } else if (mRecentShortTermAverageLux > mBrighteningLuxThreshold
+                && mRecentLongTermAverageLux > mBrighteningLuxThreshold) {
+            // The ambient environment appears to be brightening.
             if (mDebounceLuxDirection <= 0) {
                 mDebounceLuxDirection = 1;
                 mDebounceLuxTime = time;
                 if (DEBUG) {
                     Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
                             + BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
-                            + "brighteningLuxThreshold=" + brighteningLuxThreshold
+                            + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
                             + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
                             + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
                             + ", mAmbientLux=" + mAmbientLux);
                 }
             }
             long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
-            if (time >= debounceTime) {
-                mAmbientLux = mRecentShortTermAverageLux;
-                if (DEBUG) {
-                    Slog.d(TAG, "updateAmbientLux: Brightened: "
-                            + "brighteningLuxThreshold=" + brighteningLuxThreshold
-                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
-                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
-                            + ", mAmbientLux=" + mAmbientLux);
-                }
-                updateAutoBrightness(true);
-            } else {
+            if (time < debounceTime) {
                 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
+                return;
             }
-            return;
-        }
-
-        // Determine whether the ambient environment appears to be darkening.
-        float darkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
-        if (mRecentShortTermAverageLux < darkeningLuxThreshold
-                && mRecentLongTermAverageLux < darkeningLuxThreshold) {
+            setAmbientLux(mRecentShortTermAverageLux);
+            if (DEBUG) {
+                Slog.d(TAG, "updateAmbientLux: Brightened: "
+                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
+                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
+                        + ", mAmbientLux=" + mAmbientLux);
+            }
+            updateAutoBrightness(true);
+        } else if (mRecentShortTermAverageLux < mDarkeningLuxThreshold
+                && mRecentLongTermAverageLux < mDarkeningLuxThreshold) {
+            // The ambient environment appears to be darkening.
             if (mDebounceLuxDirection >= 0) {
                 mDebounceLuxDirection = -1;
                 mDebounceLuxTime = time;
                 if (DEBUG) {
                     Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
                             + DARKENING_LIGHT_DEBOUNCE + " ms: "
-                            + "darkeningLuxThreshold=" + darkeningLuxThreshold
+                            + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
                             + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
                             + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
                             + ", mAmbientLux=" + mAmbientLux);
                 }
             }
             long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
-            if (time >= debounceTime) {
-                // Be conservative about reducing the brightness, only reduce it a little bit
-                // at a time to avoid having to bump it up again soon.
-                mAmbientLux = Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux);
-                if (DEBUG) {
-                    Slog.d(TAG, "updateAmbientLux: Darkened: "
-                            + "darkeningLuxThreshold=" + darkeningLuxThreshold
-                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
-                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
-                            + ", mAmbientLux=" + mAmbientLux);
-                }
-                updateAutoBrightness(true);
-            } else {
+            if (time < debounceTime) {
                 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
+                return;
             }
-            return;
-        }
-
-        // No change or change is within the hysteresis thresholds.
-        if (mDebounceLuxDirection != 0) {
+            // Be conservative about reducing the brightness, only reduce it a little bit
+            // at a time to avoid having to bump it up again soon.
+            setAmbientLux(Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux));
+            if (DEBUG) {
+                Slog.d(TAG, "updateAmbientLux: Darkened: "
+                        + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
+                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
+                        + ", mAmbientLux=" + mAmbientLux);
+            }
+            updateAutoBrightness(true);
+        } else if (mDebounceLuxDirection != 0) {
+            // No change or change is within the hysteresis thresholds.
             mDebounceLuxDirection = 0;
             mDebounceLuxTime = time;
             if (DEBUG) {
                 Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
-                        + "brighteningLuxThreshold=" + brighteningLuxThreshold
-                        + ", darkeningLuxThreshold=" + darkeningLuxThreshold
+                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
+                        + ", mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
                         + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
                         + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
                         + ", mAmbientLux=" + mAmbientLux);
             }
         }
 
-        // If the light level does not change, then the sensor may not report
-        // a new value.  This can cause problems for the auto-brightness algorithm
-        // because the filters might not be updated.  To work around it, we want to
-        // make sure to update the filters whenever the observed light level could
-        // possibly exceed one of the hysteresis thresholds.
-        if (mLastObservedLux > brighteningLuxThreshold
-                || mLastObservedLux < darkeningLuxThreshold) {
+        // Now that we've done all of that, we haven't yet posted a debounce
+        // message. So consider the case where current lux is beyond the
+        // threshold. It's possible that the light sensor may not report values
+        // if the light level does not change, so we need to occasionally
+        // synthesize sensor readings in order to make sure the brightness is
+        // adjusted accordingly. Note these thresholds may have changed since
+        // we entered the function because we called setAmbientLux and
+        // updateAutoBrightness along the way.
+        if (mLastObservedLux > mBrighteningLuxThreshold
+                || mLastObservedLux < mDarkeningLuxThreshold) {
             mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
                     time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
         }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/wallpaper/WallpaperManagerService.java
similarity index 97%
rename from services/java/com/android/server/WallpaperManagerService.java
rename to services/java/com/android/server/wallpaper/WallpaperManagerService.java
index 205ce71..97ea52c 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.wallpaper;
 
 import static android.os.ParcelFileDescriptor.*;
 
@@ -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;
@@ -84,7 +85,7 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 
-class WallpaperManagerService extends IWallpaperManager.Stub {
+public class WallpaperManagerService extends IWallpaperManager.Stub {
     static final String TAG = "WallpaperManagerService";
     static final boolean DEBUG = false;
 
@@ -97,7 +98,6 @@
     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
     static final String WALLPAPER = "wallpaper";
     static final String WALLPAPER_INFO = "wallpaper_info.xml";
-
     /**
      * Name of the component used to display bitmap wallpapers from either the gallery or
      * built-in wallpapers.
@@ -504,7 +504,12 @@
         }
     }
 
-    String getName() {
+    /** Called by SystemBackupAgent */
+    public String getName() {
+        // Verify caller is the system
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new RuntimeException("getName() can only be called from the system process");
+        }
         synchronized (mLock) {
             return mWallpaperMap.get(0).name;
         }
@@ -637,6 +642,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,6 +661,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.
+            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;
@@ -1146,9 +1163,7 @@
         }
 
         // We always want to have some reasonable width hint.
-        WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-        Display d = wm.getDefaultDisplay();
-        int baseSize = d.getMaximumSizeDimension();
+        int baseSize = getMaximumSizeDimension();
         if (wallpaper.width < baseSize) {
             wallpaper.width = baseSize;
         }
@@ -1157,8 +1172,18 @@
         }
     }
 
+    private int getMaximumSizeDimension() {
+        WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+        Display d = wm.getDefaultDisplay();
+        return d.getMaximumSizeDimension();
+    }
+
     // Called by SystemBackupAgent after files are restored to disk.
-    void settingsRestored() {
+    public void settingsRestored() {
+        // Verify caller is the system
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new RuntimeException("settingsRestored() can only be called from the system process");
+        }
         // TODO: If necessary, make it work for secondary users as well. This currently assumes
         // restores only to the primary user
         if (DEBUG) Slog.v(TAG, "settingsRestored");
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index b7a6c5f..78e9157 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..b1d67de 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;
+    int configChanges;
     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..e65aecb 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();
     }
 
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 fbd610c..a191dbc 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -290,8 +290,6 @@
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
-    private final boolean mHeadless;
-
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -575,10 +573,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();
 
@@ -728,7 +729,6 @@
                 com.android.internal.R.bool.config_sf_limitedAlpha);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerService = displayManager;
-        mHeadless = displayManager.isHeadless();
         mDisplaySettings = new DisplaySettings(context);
         mDisplaySettings.readSettingsLocked();
 
@@ -3387,16 +3387,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");
@@ -3428,6 +3429,7 @@
             atoken.appFullscreen = fullscreen;
             atoken.showWhenLocked = showWhenLocked;
             atoken.requestedOrientation = requestedOrientation;
+            atoken.configChanges = configChanges;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
@@ -3829,22 +3831,22 @@
                     + " " + mAppTransition
                     + " alwaysKeepCurrent=" + alwaysKeepCurrent
                     + " Callers=" + Debug.getCallers(3));
-            if (okToDisplay()) {
-                if (!mAppTransition.isTransitionSet() || mAppTransition.isTransitionNone()) {
+            if (!mAppTransition.isTransitionSet() || mAppTransition.isTransitionNone()) {
+                mAppTransition.setAppTransition(transit);
+            } else if (!alwaysKeepCurrent) {
+                if (transit == AppTransition.TRANSIT_TASK_OPEN
+                        && mAppTransition.isTransitionEqual(
+                                AppTransition.TRANSIT_TASK_CLOSE)) {
+                    // Opening a new task always supersedes a close for the anim.
                     mAppTransition.setAppTransition(transit);
-                } else if (!alwaysKeepCurrent) {
-                    if (transit == AppTransition.TRANSIT_TASK_OPEN
-                            && mAppTransition.isTransitionEqual(
-                                    AppTransition.TRANSIT_TASK_CLOSE)) {
-                        // Opening a new task always supersedes a close for the anim.
-                        mAppTransition.setAppTransition(transit);
-                    } else if (transit == AppTransition.TRANSIT_ACTIVITY_OPEN
-                            && mAppTransition.isTransitionEqual(
-                                AppTransition.TRANSIT_ACTIVITY_CLOSE)) {
-                        // Opening a new activity always supersedes a close for the anim.
-                        mAppTransition.setAppTransition(transit);
-                    }
+                } else if (transit == AppTransition.TRANSIT_ACTIVITY_OPEN
+                        && mAppTransition.isTransitionEqual(
+                            AppTransition.TRANSIT_ACTIVITY_CLOSE)) {
+                    // Opening a new activity always supersedes a close for the anim.
+                    mAppTransition.setAppTransition(transit);
                 }
+            }
+            if (okToDisplay()) {
                 mAppTransition.prepare();
                 mStartingIconInTransition = false;
                 mSkipAppTransitionAnimation = false;
@@ -4304,10 +4306,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) {
@@ -4783,7 +4781,6 @@
                     displayContent.moveHomeStackBox(isHomeStackTask);
                 }
                 stack.moveTaskToTop(task);
-                displayContent.moveStack(stack, true);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -4837,7 +4834,6 @@
                         weight);
                 if (stack != null) {
                     mStackIdToStack.put(stackId, stack);
-                    displayContent.moveStack(stack, true);
                     performLayoutAndPlaceSurfacesLocked();
                     return;
                 }
@@ -4869,6 +4865,7 @@
                 return;
             }
             final TaskStack stack = task.mStack;
+            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
             stack.removeTask(task);
             stack.getDisplayContent().layoutNeeded = true;
         }
@@ -5249,7 +5246,7 @@
 
     public void performBootTimeout() {
         synchronized(mWindowMap) {
-            if (mDisplayEnabled || mHeadless) {
+            if (mDisplayEnabled) {
                 return;
             }
             Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
@@ -5433,7 +5430,6 @@
     // only allow disables from pids which have count on, etc.
     @Override
     public void showStrictModeViolation(boolean on) {
-        if (mHeadless) return;
         int pid = Binder.getCallingPid();
         mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
     }
@@ -8252,7 +8248,10 @@
             // 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())
+                    || win.isConfigChanged() && (win.mAttrs.type == TYPE_KEYGUARD ||
+                            (win.mAppToken != null && (win.mAppToken.configChanges &
+                            (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION))
+                                    != 0))
                     || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
                 if (!win.mLayoutAttached) {
                     if (initial) {
@@ -8766,6 +8765,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) {
@@ -8794,22 +8801,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) {
@@ -8887,7 +8896,7 @@
         mInnerFields.mScreenBrightness = -1;
         mInnerFields.mButtonBrightness = -1;
         mInnerFields.mUserActivityTimeout = -1;
-        mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
+        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
 
         mTransactionSequence++;
 
@@ -8922,10 +8931,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 {
@@ -9134,20 +9141,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/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index ab429fd..e3a1aa6 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1957,6 +1957,27 @@
     }
 
     /**
+     * Process phone number for CDMA, converting plus code using the home network number format.
+     * This is used for outgoing SMS messages.
+     *
+     * @param dialStr the original dial string
+     * @return the converted dial string
+     * @hide for internal use
+     */
+    public static String cdmaCheckAndProcessPlusCodeForSms(String dialStr) {
+        if (!TextUtils.isEmpty(dialStr)) {
+            if (isReallyDialable(dialStr.charAt(0)) && isNonSeparator(dialStr)) {
+                String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
+                if (!TextUtils.isEmpty(defaultIso)) {
+                    int format = getFormatTypeFromCountryCode(defaultIso);
+                    return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr, format, format);
+                }
+            }
+        }
+        return dialStr;
+    }
+
+    /**
      * This function should be called from checkAndProcessPlusCode only
      * And it is used for test purpose also.
      *
diff --git a/telephony/java/android/telephony/ThirdPartyCallListener.java b/telephony/java/android/telephony/ThirdPartyCallListener.java
new file mode 100644
index 0000000..81bbf6c
--- /dev/null
+++ b/telephony/java/android/telephony/ThirdPartyCallListener.java
@@ -0,0 +1,84 @@
+/*
+ * 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.telephony;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+
+/**
+ * Interface provided to {@link android.telephony.ThirdPartyCallService}. The service can use this
+ * to notify the listener of changes to the call state.
+ */
+public class ThirdPartyCallListener {
+    private final IThirdPartyCallListener mListener;
+
+    // Call end reason. TODO: rename this to DisconnectCause once they are public.
+    public static final int CALL_END_NORMAL = 1;
+    public static final int CALL_END_INCOMING_MISSED = 2;
+    public static final int CALL_END_OTHER = 3;
+
+    public ThirdPartyCallListener(IThirdPartyCallListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Invalid listener");
+        }
+        mListener = listener;
+    }
+
+    /**
+     * Called by the service when a call provider is available to perform the outgoing or incoming
+     * call.
+     */
+    public void onCallProviderAttached(ThirdPartyCallProvider callProvider) {
+        try {
+            mListener.onCallProviderAttached(callProvider.getCallback());
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Notifies the listener that ringing has started for this call.
+     */
+    public void onRingingStarted() {
+        try {
+            mListener.onRingingStarted();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Notifies the listener that the call has been successfully established.
+     */
+    public void onCallEstablished() {
+        try {
+            mListener.onCallEstablished();
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Notifies the listener that the call has ended.
+     */
+    public void onCallEnded(int reason) {
+        try {
+            mListener.onCallEnded(reason);
+        } catch (RemoteException e) {
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/ThirdPartyCallProvider.java b/telephony/java/android/telephony/ThirdPartyCallProvider.java
new file mode 100644
index 0000000..bd8a1ea
--- /dev/null
+++ b/telephony/java/android/telephony/ThirdPartyCallProvider.java
@@ -0,0 +1,107 @@
+/*
+ * 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.telephony;
+
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.telephony.IThirdPartyCallProvider;
+
+/**
+ * Interface sent to {@link android.telephony.ThirdPartyCallListener#onCallProviderAttached
+ * onCallProviderAttached}. This is used to control an outgoing or an incoming call.
+ */
+public class ThirdPartyCallProvider {
+    private static final int MSG_MUTE = 1;
+    private static final int MSG_HANGUP = 2;
+    private static final int MSG_INCOMING_CALL_ACCEPT = 3;
+    private static final int MSG_SEND_DTMF = 4;
+
+    /**
+     * Mutes or unmutes the call.
+     */
+    public void mute(boolean shouldMute) {
+        // default implementation empty
+    }
+
+    /**
+     * Ends the current call. If this is an unanswered incoming call then the call is rejected.
+     */
+    public void hangup() {
+        // default implementation empty
+    }
+
+   /**
+     * Accepts the incoming call.
+     */
+    public void incomingCallAccept() {
+        // default implementation empty
+    }
+
+    /**
+     * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
+     */
+    public void sendDtmf(char c) {
+        // default implementation empty
+    }
+
+    IThirdPartyCallProvider getCallback() {
+        return mCallback;
+    }
+
+    private final IThirdPartyCallProvider mCallback = new IThirdPartyCallProvider.Stub() {
+        @Override
+        public void mute(boolean shouldMute) {
+            Message.obtain(mHandler, MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget();
+        }
+
+        @Override
+        public void hangup() {
+            Message.obtain(mHandler, MSG_HANGUP).sendToTarget();
+        }
+
+        @Override
+        public void incomingCallAccept() {
+            Message.obtain(mHandler, MSG_INCOMING_CALL_ACCEPT).sendToTarget();
+        }
+
+        @Override
+        public void sendDtmf(char c) {
+            Message.obtain(mHandler, MSG_SEND_DTMF, (int) c, 0).sendToTarget();
+        }
+    };
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_MUTE:
+                    mute(msg.arg1 != 0);
+                    break;
+                case MSG_HANGUP:
+                    hangup();
+                    break;
+                case MSG_INCOMING_CALL_ACCEPT:
+                    incomingCallAccept();
+                    break;
+                case MSG_SEND_DTMF:
+                    sendDtmf((char) msg.arg1);
+                    break;
+            }
+        }
+    };
+}
diff --git a/telephony/java/android/telephony/ThirdPartyCallService.java b/telephony/java/android/telephony/ThirdPartyCallService.java
new file mode 100644
index 0000000..e82820f
--- /dev/null
+++ b/telephony/java/android/telephony/ThirdPartyCallService.java
@@ -0,0 +1,95 @@
+/*
+ * 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.telephony;
+
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Pair;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+import com.android.internal.telephony.IThirdPartyCallService;
+
+/**
+ * Interface provided by a service to start outgoing calls and attach to incoming calls.
+ */
+public class ThirdPartyCallService {
+    private static final int MSG_OUTGOING_CALL_INITIATE = 1;
+    private static final int MSG_INCOMING_CALL_ATTACH = 2;
+
+    /**
+     * Call to start a new outgoing call.
+     */
+    public void outgoingCallInitiate(ThirdPartyCallListener listener, String number) {
+        // default implementation empty
+    }
+
+    /**
+     * Call to attach to an incoming call.
+     */
+    public void incomingCallAttach(ThirdPartyCallListener listener, String callId) {
+        // default implementation empty
+    }
+
+    /**
+     * Returns an IBinder instance that can returned from the service's onBind function.
+     */
+    public IBinder getBinder() {
+        return mCallback;
+    }
+
+    private final IThirdPartyCallService.Stub mCallback = new IThirdPartyCallService.Stub() {
+        @Override
+        public void outgoingCallInitiate(IThirdPartyCallListener listener, String number) {
+            Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.IThirdPartyCallService.out");
+            Message.obtain(mHandler, MSG_OUTGOING_CALL_INITIATE,
+                    Pair.create(listener, number)).sendToTarget();
+        }
+
+        @Override
+        public void incomingCallAttach(IThirdPartyCallListener listener, String callId) {
+            Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.IThirdPartyCallService.in");
+            Message.obtain(mHandler, MSG_INCOMING_CALL_ATTACH,
+                    Pair.create(listener, callId)).sendToTarget();
+        }
+    };
+
+    private final Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage: " + msg.what);
+            switch (msg.what) {
+                case MSG_OUTGOING_CALL_INITIATE: {
+                    Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage out");
+                    Pair<IThirdPartyCallListener, String> pair =
+                            (Pair<IThirdPartyCallListener, String>) msg.obj;
+                    ThirdPartyCallListener listener = new ThirdPartyCallListener(pair.first);
+                    outgoingCallInitiate(listener, pair.second);
+                    break;
+                }
+                case MSG_INCOMING_CALL_ATTACH: {
+                    Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage in");
+                    Pair<IThirdPartyCallListener, String> pair =
+                            (Pair<IThirdPartyCallListener, String>) msg.obj;
+                    ThirdPartyCallListener listener = new ThirdPartyCallListener(pair.first);
+                    incomingCallAttach(listener, pair.second);
+                    break;
+                }
+            }
+        }
+    };
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
new file mode 100644
index 0000000..bcf2d81
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
@@ -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.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallProvider;
+
+/**
+ * Interface provided to ThirdPartyCallService. The service can use this to notify the listener of
+ * changes to the call state.
+ */
+oneway interface IThirdPartyCallListener {
+    /**
+     * Called by the service when a call provider is available to perform the outgoing or incoming
+     * call.
+     */
+    void onCallProviderAttached(IThirdPartyCallProvider callProvider);
+
+    /**
+     * Notifies the listener that ringing has started for this call.
+     */
+    void onRingingStarted();
+
+    /**
+     * Notifies the listener that the call has been successfully established.
+     */
+    void onCallEstablished();
+
+    /**
+     * Notifies the listener that the call has ended.
+     */
+    void onCallEnded(int reason);
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
new file mode 100644
index 0000000..a9d67a4
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
@@ -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.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+
+/**
+ * Interface sent to ThirdPartyCallListener.onCallProviderAttached. This is used to control an
+ * outgoing or incoming call.
+ */
+oneway interface IThirdPartyCallProvider {
+    /**
+     * Mutes or unmutes the call.
+     */
+    void mute(boolean shouldMute);
+
+    /**
+     * Ends the current call. If this is an unanswered incoming call then the call is rejected (for
+     * example, a notification is sent to a server that the user declined the call).
+     */
+    void hangup();
+
+    /**
+     * Accepts the incoming call.
+     */
+    void incomingCallAccept();
+
+    /**
+     * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
+     */
+    void sendDtmf(char c);
+}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
new file mode 100644
index 0000000..c9ee4ed
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.telephony;
+
+import com.android.internal.telephony.IThirdPartyCallListener;
+
+/**
+ * Interface provided by a service to start outgoing calls and attach to incoming calls.
+ */
+oneway interface IThirdPartyCallService {
+    /**
+     * Call to start a new outgoing call.
+     */
+    void outgoingCallInitiate(IThirdPartyCallListener listener, String number);
+
+    /**
+     * Call to attach to an incoming call.
+     */
+    void incomingCallAttach(IThirdPartyCallListener listener, String callId);
+}
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/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bfcc208..4a6b1ff 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -115,7 +115,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 1fa7e85..4c887cb 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 8c92e55..4f2af78 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -56,6 +56,8 @@
 import android.net.wifi.p2p.WifiP2pManager;
 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;
@@ -410,7 +412,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;
@@ -620,6 +623,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");
@@ -832,8 +844,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() {
@@ -852,6 +870,8 @@
     }
 
     private void startBatchedScan() {
+        if (mBatchedScanSettings == null) return;
+
         if (mDhcpActive) {
             if (DBG) log("not starting Batched Scans due to DHCP");
             return;
@@ -863,10 +883,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);
@@ -909,25 +929,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) {
@@ -1155,6 +1181,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;
@@ -1855,6 +1919,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");
@@ -2294,9 +2361,7 @@
 
         mDhcpActive = false;
 
-        if (mBatchedScanSettings != null) {
-            startBatchedScan();
-        }
+        startBatchedScan();
     }
 
     private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) {
@@ -2434,7 +2499,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();
@@ -2946,9 +3011,7 @@
 
             mDhcpActive = false;
 
-            if (mBatchedScanSettings != null) {
-                startBatchedScan();
-            }
+            startBatchedScan();
 
             if (mOperationalMode != CONNECT_MODE) {
                 mWifiNative.disconnect();
@@ -3007,8 +3070,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;
@@ -3146,9 +3211,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);