Merge "Add native method delegates to layoutlib"
diff --git a/api/current.txt b/api/current.txt
index eb6de96..2e38627 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -314,6 +314,7 @@
     field public static final int backgroundSplit = 16843659; // 0x101038b
     field public static final int backgroundStacked = 16843658; // 0x101038a
     field public static final int backupAgent = 16843391; // 0x101027f
+    field public static final int banner = 16843762; // 0x10103f2
     field public static final int baseline = 16843548; // 0x101031c
     field public static final int baselineAlignBottom = 16843042; // 0x1010122
     field public static final int baselineAligned = 16843046; // 0x1010126
@@ -345,7 +346,7 @@
     field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
     field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
     field public static final deprecated int capitalize = 16843113; // 0x1010169
-    field public static final int castsShadow = 16843774; // 0x10103fe
+    field public static final int castsShadow = 16843775; // 0x10103ff
     field public static final int category = 16843752; // 0x10103e8
     field public static final int centerBright = 16842956; // 0x10100cc
     field public static final int centerColor = 16843275; // 0x101020b
@@ -399,10 +400,10 @@
     field public static final int content = 16843355; // 0x101025b
     field public static final int contentAuthority = 16843408; // 0x1010290
     field public static final int contentDescription = 16843379; // 0x1010273
-    field public static final int controlX1 = 16843768; // 0x10103f8
-    field public static final int controlX2 = 16843770; // 0x10103fa
-    field public static final int controlY1 = 16843769; // 0x10103f9
-    field public static final int controlY2 = 16843771; // 0x10103fb
+    field public static final int controlX1 = 16843769; // 0x10103f9
+    field public static final int controlX2 = 16843771; // 0x10103fb
+    field public static final int controlY1 = 16843770; // 0x10103fa
+    field public static final int controlY2 = 16843772; // 0x10103fc
     field public static final int cropToPadding = 16843043; // 0x1010123
     field public static final int cursorVisible = 16843090; // 0x1010152
     field public static final int customNavigationLayout = 16843474; // 0x10102d2
@@ -505,7 +506,7 @@
     field public static final int fastScrollOverlayPosition = 16843578; // 0x101033a
     field public static final int fastScrollPreviewBackgroundLeft = 16843575; // 0x1010337
     field public static final int fastScrollPreviewBackgroundRight = 16843576; // 0x1010338
-    field public static final int fastScrollStyle = 16843763; // 0x10103f3
+    field public static final int fastScrollStyle = 16843764; // 0x10103f4
     field public static final int fastScrollTextColor = 16843609; // 0x1010359
     field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
     field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
@@ -531,7 +532,7 @@
     field public static final int format12Hour = 16843722; // 0x10103ca
     field public static final int format24Hour = 16843723; // 0x10103cb
     field public static final int fragment = 16843491; // 0x10102e3
-    field public static final int fragmentBreadCrumbsStyle = 16843762; // 0x10103f2
+    field public static final int fragmentBreadCrumbsStyle = 16843763; // 0x10103f3
     field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
     field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8
     field public static final int fragmentFadeEnterAnimation = 16843497; // 0x10102e9
@@ -825,7 +826,7 @@
     field public static final int persistent = 16842765; // 0x101000d
     field public static final int persistentDrawingCache = 16842990; // 0x10100ee
     field public static final deprecated int phoneNumber = 16843111; // 0x1010167
-    field public static final int pinned = 16843776; // 0x1010400
+    field public static final int pinned = 16843777; // 0x1010401
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
@@ -889,7 +890,7 @@
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
-    field public static final int requiredForProfile = 16843775; // 0x10103ff
+    field public static final int requiredForProfile = 16843776; // 0x1010400
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
@@ -960,7 +961,7 @@
     field public static final int shadowRadius = 16843108; // 0x1010164
     field public static final int shape = 16843162; // 0x101019a
     field public static final int shareInterpolator = 16843195; // 0x10101bb
-    field public static final int sharedElementName = 16843772; // 0x10103fc
+    field public static final int sharedElementName = 16843773; // 0x10103fd
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
     field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1137,7 +1138,7 @@
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int timeZone = 16843724; // 0x10103cc
     field public static final int tint = 16843041; // 0x1010121
-    field public static final int tintMode = 16843767; // 0x10103f7
+    field public static final int tintMode = 16843768; // 0x10103f8
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
     field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -1159,11 +1160,11 @@
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
     field public static final int transition = 16843743; // 0x10103df
-    field public static final int transitionGroup = 16843773; // 0x10103fd
+    field public static final int transitionGroup = 16843774; // 0x10103fe
     field public static final int transitionOrdering = 16843744; // 0x10103e0
     field public static final int translationX = 16843554; // 0x1010322
     field public static final int translationY = 16843555; // 0x1010323
-    field public static final int translationZ = 16843766; // 0x10103f6
+    field public static final int translationZ = 16843767; // 0x10103f7
     field public static final int type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
@@ -1220,8 +1221,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 windowContentTransitionManager = 16843766; // 0x10103f6
+    field public static final int windowContentTransitions = 16843765; // 0x10103f5
     field public static final int windowDisablePreview = 16843298; // 0x1010222
     field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
     field public static final int windowEnterAnimation = 16842932; // 0x10100b4
@@ -7417,6 +7418,7 @@
     ctor public ComponentInfo();
     ctor public ComponentInfo(android.content.pm.ComponentInfo);
     ctor protected ComponentInfo(android.os.Parcel);
+    method public final int getBannerResource();
     method public final int getIconResource();
     method public final int getLogoResource();
     method public boolean isEnabled();
@@ -7520,11 +7522,13 @@
     ctor protected PackageItemInfo(android.os.Parcel);
     method protected void dumpBack(android.util.Printer, java.lang.String);
     method protected void dumpFront(android.util.Printer, java.lang.String);
+    method public android.graphics.drawable.Drawable loadBanner(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager);
     method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
+    field public int banner;
     field public int icon;
     field public int labelRes;
     field public int logo;
@@ -7552,12 +7556,16 @@
     method public abstract void clearPackagePreferredActivities(java.lang.String);
     method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
     method public abstract void extendVerificationTimeout(int, int, long);
+    method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+    method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
+    method public abstract android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int getApplicationEnabledSetting(java.lang.String);
     method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
     method public abstract android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7637,6 +7645,7 @@
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
+    field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
     field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
     field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location";
     field public static final java.lang.String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
@@ -7660,7 +7669,7 @@
     field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
     field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
     field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
-    field public static final java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
+    field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
     field public static final java.lang.String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -25474,12 +25483,16 @@
     method public void clearPackagePreferredActivities(java.lang.String);
     method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
     method public void extendVerificationTimeout(int, int, long);
+    method public android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+    method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
+    method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getApplicationEnabledSetting(java.lang.String);
     method public android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
     method public android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index e71d47d..079cf7a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -878,7 +878,7 @@
     }
 
     /**
-     * Like {@link #checkOp but instead of throwing a {@link SecurityException} it
+     * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
      * returns {@link #MODE_ERRORED}.
      */
     public int checkOpNoThrow(String op, int uid, String packageName) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 061e5a5..8165fa1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -727,6 +727,39 @@
     }
 
     @Override
+    public Drawable getActivityBanner(ComponentName activityName)
+            throws NameNotFoundException {
+        return getActivityInfo(activityName, 0).loadBanner(this);
+    }
+
+    @Override
+    public Drawable getActivityBanner(Intent intent)
+            throws NameNotFoundException {
+        if (intent.getComponent() != null) {
+            return getActivityBanner(intent.getComponent());
+        }
+
+        ResolveInfo info = resolveActivity(
+                intent, PackageManager.MATCH_DEFAULT_ONLY);
+        if (info != null) {
+            return info.activityInfo.loadBanner(this);
+        }
+
+        throw new NameNotFoundException(intent.toUri(0));
+    }
+
+    @Override
+    public Drawable getApplicationBanner(ApplicationInfo info) {
+        return info.loadBanner(this);
+    }
+
+    @Override
+    public Drawable getApplicationBanner(String packageName)
+            throws NameNotFoundException {
+        return getApplicationBanner(getApplicationInfo(packageName, 0));
+    }
+
+    @Override
     public Drawable getActivityLogo(ComponentName activityName)
             throws NameNotFoundException {
         return getActivityInfo(activityName, 0).loadLogo(this);
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 4dbcf23..7e8f285 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -128,6 +128,17 @@
         return logo != 0 ? logo : applicationInfo.logo;
     }
     
+    /**
+     * Return the banner resource identifier to use for this component. If the
+     * component defines a banner, that is used; else, the application banner is
+     * used.
+     *
+     * @return The banner associated with this component.
+     */
+    public final int getBannerResource() {
+        return banner != 0 ? banner : applicationInfo.banner;
+    }
+
     protected void dumpFront(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
         pw.println(prefix + "enabled=" + enabled + " exported=" + exported
@@ -175,6 +186,13 @@
     /**
      * @hide
      */
+    @Override protected Drawable loadDefaultBanner(PackageManager pm) {
+        return applicationInfo.loadBanner(pm);
+    }
+
+    /**
+     * @hide
+     */
     @Override
     protected Drawable loadDefaultLogo(PackageManager pm) {
         return applicationInfo.loadLogo(pm);
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index a67326e..58f1c84 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -68,6 +68,12 @@
     
     /**
      * A drawable resource identifier (in the package's resources) of this
+     * component's banner.  From the "banner" attribute or, if not set, 0.
+     */
+    public int banner;
+
+    /**
+     * A drawable resource identifier (in the package's resources) of this
      * component's logo. Logos may be larger/wider than icons and are
      * displayed by certain UI elements in place of a name or name/icon
      * combination. From the "logo" attribute or, if not set, 0. 
@@ -92,6 +98,7 @@
         nonLocalizedLabel = orig.nonLocalizedLabel;
         if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim();
         icon = orig.icon;
+        banner = orig.banner;
         logo = orig.logo;
         metaData = orig.metaData;
     }
@@ -146,6 +153,27 @@
     }
     
     /**
+     * Retrieve the current graphical banner associated with this item.  This
+     * will call back on the given PackageManager to load the banner from
+     * the application.
+     *
+     * @param pm A PackageManager from which the banner can be loaded; usually
+     * the PackageManager from which you originally retrieved this item.
+     *
+     * @return Returns a Drawable containing the item's banner.  If the item
+     * does not have a banner, this method will return null.
+     */
+    public Drawable loadBanner(PackageManager pm) {
+        if (banner != 0) {
+            Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo());
+            if (dr != null) {
+                return dr;
+            }
+        }
+        return loadDefaultBanner(pm);
+    }
+
+    /**
      * Retrieve the default graphical icon associated with this item.
      * 
      * @param pm A PackageManager from which the icon can be loaded; usually
@@ -159,7 +187,22 @@
     protected Drawable loadDefaultIcon(PackageManager pm) {
         return pm.getDefaultActivityIcon();
     }
-    
+
+    /**
+     * Retrieve the default graphical banner associated with this item.
+     *
+     * @param pm A PackageManager from which the banner can be loaded; usually
+     * the PackageManager from which you originally retrieved this item.
+     *
+     * @return Returns a Drawable containing the item's default banner
+     * or null if no default logo is available.
+     *
+     * @hide
+     */
+    protected Drawable loadDefaultBanner(PackageManager pm) {
+        return null;
+    }
+
     /**
      * Retrieve the current graphical logo associated with this item. This
      * will call back on the given PackageManager to load the logo from
@@ -224,10 +267,11 @@
             pw.println(prefix + "name=" + name);
         }
         pw.println(prefix + "packageName=" + packageName);
-        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) {
+        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
             pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
                     + " nonLocalizedLabel=" + nonLocalizedLabel
-                    + " icon=0x" + Integer.toHexString(icon));
+                    + " icon=0x" + Integer.toHexString(icon)
+                    + " banner=0x" + Integer.toHexString(banner));
         }
     }
     
@@ -243,6 +287,7 @@
         dest.writeInt(icon);
         dest.writeInt(logo);
         dest.writeBundle(metaData);
+        dest.writeInt(banner);
     }
     
     protected PackageItemInfo(Parcel source) {
@@ -254,6 +299,7 @@
         icon = source.readInt();
         logo = source.readInt();
         metaData = source.readBundle();
+        banner = source.readInt();
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b648930..e86833b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1233,6 +1233,26 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports leanback UI. This is
+     * typically used in a living room television experience, but is a software
+     * feature unlike {@link #FEATURE_TELEVISION}. Devices running with this
+     * feature will use resources associated with the "television" UI mode.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_LEANBACK = "android.software.leanback";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports only leanback UI. Only
+     * applications designed for this experience should be run, though this is
+     * not enforced by the system.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -1252,6 +1272,7 @@
      * room television experience: displayed on a big screen, where the user
      * is sitting far away from it, and the dominant form of input will be
      * something like a DPAD, not through touch or mouse.
+     * @deprecated use {@link #FEATURE_LEANBACK} instead.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEVISION = "android.hardware.type.television";
@@ -2400,9 +2421,43 @@
             throws NameNotFoundException;
 
     /**
+     * Retrieve the banner associated with an activity. Given the full name of
+     * an activity, retrieves the information about it and calls
+     * {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its
+     * banner. If the activity cannot be found, NameNotFoundException is thrown.
+     *
+     * @param activityName Name of the activity whose banner is to be retrieved.
+     * @return Returns the image of the banner, or null if the activity has no
+     *         banner specified.
+     * @throws NameNotFoundException Thrown if the resources for the given
+     *             activity could not be loaded.
+     * @see #getActivityBanner(Intent)
+     */
+    public abstract Drawable getActivityBanner(ComponentName activityName)
+            throws NameNotFoundException;
+
+    /**
+     * Retrieve the banner associated with an Intent. If intent.getClassName()
+     * is set, this simply returns the result of
+     * getActivityBanner(intent.getClassName()). Otherwise it resolves the
+     * intent's component and returns the banner associated with the resolved
+     * component. If intent.getClassName() cannot be found or the Intent cannot
+     * be resolved to a component, NameNotFoundException is thrown.
+     *
+     * @param intent The intent for which you would like to retrieve a banner.
+     * @return Returns the image of the banner, or null if the activity has no
+     *         banner specified.
+     * @throws NameNotFoundException Thrown if the resources for application
+     *             matching the given intent could not be loaded.
+     * @see #getActivityBanner(ComponentName)
+     */
+    public abstract Drawable getActivityBanner(Intent intent)
+            throws NameNotFoundException;
+
+    /**
      * Return the generic icon for an activity that is used when no specific
      * icon is defined.
-     *
+     * 
      * @return Drawable Image of the icon.
      */
     public abstract Drawable getDefaultActivityIcon();
@@ -2440,19 +2495,43 @@
             throws NameNotFoundException;
 
     /**
-     * Retrieve the logo associated with an activity.  Given the full name of
-     * an activity, retrieves the information about it and calls
-     * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo.
-     * If the activity cannot be found, NameNotFoundException is thrown.
+     * Retrieve the banner associated with an application.
+     *
+     * @param info Information about application being queried.
+     * @return Returns the image of the banner or null if the application has no
+     *         banner specified.
+     * @see #getApplicationBanner(String)
+     */
+    public abstract Drawable getApplicationBanner(ApplicationInfo info);
+
+    /**
+     * Retrieve the banner associated with an application. Given the name of the
+     * application's package, retrieves the information about it and calls
+     * getApplicationIcon() to return its banner. If the application cannot be
+     * found, NameNotFoundException is thrown.
+     *
+     * @param packageName Name of the package whose application banner is to be
+     *            retrieved.
+     * @return Returns the image of the banner or null if the application has no
+     *         banner specified.
+     * @throws NameNotFoundException Thrown if the resources for the given
+     *             application could not be loaded.
+     * @see #getApplicationBanner(ApplicationInfo)
+     */
+    public abstract Drawable getApplicationBanner(String packageName)
+            throws NameNotFoundException;
+
+    /**
+     * Retrieve the logo associated with an activity. Given the full name of an
+     * activity, retrieves the information about it and calls
+     * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its
+     * logo. If the activity cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose logo is to be retrieved.
-     *
-     * @return Returns the image of the logo or null if the activity has no
-     * logo specified.
-     *
+     * @return Returns the image of the logo or null if the activity has no logo
+     *         specified.
      * @throws NameNotFoundException Thrown if the resources for the given
-     * activity could not be loaded.
-     *
+     *             activity could not be loaded.
      * @see #getActivityLogo(Intent)
      */
     public abstract Drawable getActivityLogo(ComponentName activityName)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c222003..f76aada 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -167,18 +167,20 @@
         final int labelRes;
         final int iconRes;
         final int logoRes;
+        final int bannerRes;
         
         String tag;
         TypedArray sa;
         
         ParsePackageItemArgs(Package _owner, String[] _outError,
-                int _nameRes, int _labelRes, int _iconRes, int _logoRes) {
+                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
             owner = _owner;
             outError = _outError;
             nameRes = _nameRes;
             labelRes = _labelRes;
             iconRes = _iconRes;
             logoRes = _logoRes;
+            bannerRes = _bannerRes;
         }
     }
     
@@ -190,10 +192,10 @@
         int flags;
         
         ParseComponentArgs(Package _owner, String[] _outError,
-                int _nameRes, int _labelRes, int _iconRes, int _logoRes,
+                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
                 String[] _sepProcesses, int _processRes,
                 int _descriptionRes, int _enabledRes) {
-            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes);
+            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes);
             sepProcesses = _sepProcesses;
             processRes = _processRes;
             descriptionRes = _descriptionRes;
@@ -1688,7 +1690,8 @@
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
-                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) {
+                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
+                com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
             sa.recycle();
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return null;
@@ -1731,7 +1734,8 @@
                 com.android.internal.R.styleable.AndroidManifestPermission_name,
                 com.android.internal.R.styleable.AndroidManifestPermission_label,
                 com.android.internal.R.styleable.AndroidManifestPermission_icon,
-                com.android.internal.R.styleable.AndroidManifestPermission_logo)) {
+                com.android.internal.R.styleable.AndroidManifestPermission_logo,
+                com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
             sa.recycle();
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return null;
@@ -1800,7 +1804,8 @@
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
-                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) {
+                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
+                com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
             sa.recycle();
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return null;
@@ -1845,7 +1850,8 @@
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
-                    com.android.internal.R.styleable.AndroidManifestInstrumentation_logo);
+                    com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
+                    com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
             mParseInstrumentationArgs.tag = "<instrumentation>";
         }
         
@@ -1961,6 +1967,8 @@
                 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
         ai.logo = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
+        ai.banner = sa.getResourceId(
+                com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
         ai.theme = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
         ai.descriptionRes = sa.getResourceId(
@@ -2256,7 +2264,7 @@
 
     private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
             String[] outError, String tag, TypedArray sa,
-            int nameRes, int labelRes, int iconRes, int logoRes) {
+            int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
         String name = sa.getNonConfigurationString(nameRes, 0);
         if (name == null) {
             outError[0] = tag + " does not specify android:name";
@@ -2280,6 +2288,11 @@
             outInfo.logo = logoVal;
         }
 
+        int bannerVal = sa.getResourceId(bannerRes, 0);
+        if (bannerVal != 0) {
+            outInfo.banner = bannerVal;
+        }
+
         TypedValue v = sa.peekValue(labelRes);
         if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
             outInfo.nonLocalizedLabel = v.coerceToString();
@@ -2303,6 +2316,7 @@
                     com.android.internal.R.styleable.AndroidManifestActivity_label,
                     com.android.internal.R.styleable.AndroidManifestActivity_icon,
                     com.android.internal.R.styleable.AndroidManifestActivity_logo,
+                    com.android.internal.R.styleable.AndroidManifestActivity_banner,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestActivity_process,
                     com.android.internal.R.styleable.AndroidManifestActivity_description,
@@ -2588,6 +2602,7 @@
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
+                    com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
                     mSeparateProcesses,
                     0,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
@@ -2622,6 +2637,7 @@
         info.flags = target.info.flags;
         info.icon = target.info.icon;
         info.logo = target.info.logo;
+        info.banner = target.info.banner;
         info.labelRes = target.info.labelRes;
         info.nonLocalizedLabel = target.info.nonLocalizedLabel;
         info.launchMode = target.info.launchMode;
@@ -2735,6 +2751,7 @@
                     com.android.internal.R.styleable.AndroidManifestProvider_label,
                     com.android.internal.R.styleable.AndroidManifestProvider_icon,
                     com.android.internal.R.styleable.AndroidManifestProvider_logo,
+                    com.android.internal.R.styleable.AndroidManifestProvider_banner,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestProvider_process,
                     com.android.internal.R.styleable.AndroidManifestProvider_description,
@@ -3041,6 +3058,7 @@
                     com.android.internal.R.styleable.AndroidManifestService_label,
                     com.android.internal.R.styleable.AndroidManifestService_icon,
                     com.android.internal.R.styleable.AndroidManifestService_logo,
+                    com.android.internal.R.styleable.AndroidManifestService_banner,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestService_process,
                     com.android.internal.R.styleable.AndroidManifestService_description,
@@ -3338,6 +3356,9 @@
         outInfo.logo = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
 
+        outInfo.banner = sa.getResourceId(
+                com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
+
         sa.recycle();
 
         int outerDepth = parser.getDepth();
@@ -3707,6 +3728,11 @@
                 outInfo.logo = logoVal;
             }
 
+            int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
+            if (bannerVal != 0) {
+                outInfo.banner = bannerVal;
+            }
+
             TypedValue v = args.sa.peekValue(args.labelRes);
             if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
                 outInfo.nonLocalizedLabel = v.coerceToString();
@@ -4131,6 +4157,7 @@
         public CharSequence nonLocalizedLabel;
         public int icon;
         public int logo;
+        public int banner;
         public int preferred;
     }
 
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 875e8de..4a743a5 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -140,12 +140,33 @@
         mContext.registerReceiver(mExternalReceiver, sdFilter);
     }
 
+    private final void handlePackageEvent(Intent intent, int userId) {
+        // Don't regenerate the services map when the package is removed or its
+        // ASEC container unmounted as a step in replacement.  The subsequent
+        // _ADDED / _AVAILABLE call will regenerate the map in the final state.
+        final String action = intent.getAction();
+        // it's a new-component action if it isn't some sort of removal
+        final boolean isRemoval = Intent.ACTION_PACKAGE_REMOVED.equals(action)
+                || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action);
+        // if it's a removal, is it part of an update-in-place step?
+        final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+
+        if (isRemoval && replacing) {
+            // package is going away, but it's the middle of an upgrade: keep the current
+            // state and do nothing here.  This clause is intentionally empty.
+        } else {
+            // either we're adding/changing, or it's a removal without replacement, so
+            // we need to recalculate the set of available services
+            generateServicesMap(userId);
+        }
+    }
+
     private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
             if (uid != -1) {
-                generateServicesMap(UserHandle.getUserId(uid));
+                handlePackageEvent(intent, UserHandle.getUserId(uid));
             }
         }
     };
@@ -154,7 +175,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             // External apps can't coexist with multi-user, so scan owner
-            generateServicesMap(UserHandle.USER_OWNER);
+            handlePackageEvent(intent, UserHandle.USER_OWNER);
         }
     };
 
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index b615600..806a89d 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -475,6 +475,12 @@
          * @param colorModes The color mode bit mask.
          * @param defaultColorMode The default color mode.
          * @return This builder.
+         * <p>
+         * <strong>Note:</strong> On platform version 19 (Kitkat) specifying
+         * only PrintAttributes#COLOR_MODE_MONOCHROME leads to a print spooler
+         * crash. Hence, you should declare either both color modes or
+         * PrintAttributes#COLOR_MODE_COLOR.
+         * </p>
          *
          * @throws IllegalArgumentException If color modes contains an invalid
          *         mode bit or if the default color mode is invalid.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 2efbca2..0a27840 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -62,6 +62,21 @@
          a reference to a Drawable resource containing the image definition. -->
     <attr name="icon" format="reference" />
 
+    <!-- A Drawable resource providing an extended graphical banner for its
+         associated item. Use with the application tag (to supply a default
+         banner for all application activities), or with the activity, tag to
+         supply a banner for a specific activity.
+
+         <p>The given banner will be used to display to the user a graphical
+         representation of an activity in the Leanback application launcher.
+         Since banners are displayed only in the Leanback launcher, they should
+         only be used with activities (and applications) that support Leanback
+         mode. These are activities that handle Intents of category
+         {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER
+         Intent.CATEGORY_LEANBACK_LAUNCHER}.
+         <p>This must be a reference to a Drawable resource containing the image definition. -->
+    <attr name="banner" format="reference" />
+
     <!-- A Drawable resource providing an extended graphical logo for its
          associated item. Use with the application tag (to supply a default
          logo for all application components), or with the activity, receiver,
@@ -899,6 +914,7 @@
         <attr name="theme" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
         <attr name="permission" />
@@ -982,6 +998,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permissionGroup" />
         <attr name="description" />
@@ -1008,6 +1025,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
         <attr name="permissionGroupFlags" />
@@ -1040,6 +1058,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
     </declare-styleable>
     
@@ -1306,6 +1325,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="process" />
         <attr name="authorities" />
@@ -1387,6 +1407,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <attr name="process" />
@@ -1429,6 +1450,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <attr name="process" />
@@ -1463,6 +1485,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="launchMode" />
         <attr name="screenOrientation" />
@@ -1526,6 +1549,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <!-- Specify whether the activity-alias is enabled or not (that is, can be instantiated by the system).
@@ -1597,6 +1621,7 @@
          parent="AndroidManifestActivity AndroidManifestReceiver AndroidManifestService">
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="priority" />
     </declare-styleable>
@@ -1725,6 +1750,7 @@
         <attr name="targetPackage" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="handleProfiling" />
         <attr name="functionalTest" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d58e8ad..25c8baa 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2088,6 +2088,13 @@
   <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" id="0x010301e4" />
 
 <!-- ===============================================================
+     Resources added in version 20 of the platform
+     =============================================================== -->
+  <eat-comment />
+
+  <public type="attr" name="banner" id="0x10103f2" />
+
+<!-- ===============================================================
      Resources added in version 21 of the platform
      =============================================================== -->
   <eat-comment />
diff --git a/docs/html/images/screens_support/avds-config.png b/docs/html/images/screens_support/avds-config.png
index 97bd5f6..e609447 100644
--- a/docs/html/images/screens_support/avds-config.png
+++ b/docs/html/images/screens_support/avds-config.png
Binary files differ
diff --git a/docs/html/images/tools/as-camera-icon.png b/docs/html/images/tools/as-camera-icon.png
new file mode 100644
index 0000000..419a88d
--- /dev/null
+++ b/docs/html/images/tools/as-camera-icon.png
Binary files differ
diff --git a/docs/html/images/tools/as-error.png b/docs/html/images/tools/as-error.png
new file mode 100644
index 0000000..8865f54
--- /dev/null
+++ b/docs/html/images/tools/as-error.png
Binary files differ
diff --git a/docs/html/images/tools/as-fr-device.png b/docs/html/images/tools/as-fr-device.png
new file mode 100644
index 0000000..aec3bce
--- /dev/null
+++ b/docs/html/images/tools/as-fr-device.png
Binary files differ
diff --git a/docs/html/images/tools/as-fr-icon.png b/docs/html/images/tools/as-fr-icon.png
new file mode 100644
index 0000000..9252ca1
--- /dev/null
+++ b/docs/html/images/tools/as-fr-icon.png
Binary files differ
diff --git a/docs/html/images/tools/as-frag-ex.png b/docs/html/images/tools/as-frag-ex.png
new file mode 100644
index 0000000..775fa5e
--- /dev/null
+++ b/docs/html/images/tools/as-frag-ex.png
Binary files differ
diff --git a/docs/html/images/tools/as-grid-layout.png b/docs/html/images/tools/as-grid-layout.png
new file mode 100644
index 0000000..41b933a
--- /dev/null
+++ b/docs/html/images/tools/as-grid-layout.png
Binary files differ
diff --git a/docs/html/images/tools/as-i18n-icon.png b/docs/html/images/tools/as-i18n-icon.png
new file mode 100644
index 0000000..d35568f
--- /dev/null
+++ b/docs/html/images/tools/as-i18n-icon.png
Binary files differ
diff --git a/docs/html/images/tools/as-preview-chrome.png b/docs/html/images/tools/as-preview-chrome.png
new file mode 100644
index 0000000..716b8d7
--- /dev/null
+++ b/docs/html/images/tools/as-preview-chrome.png
Binary files differ
diff --git a/docs/html/images/tools/as-preview-icon.png b/docs/html/images/tools/as-preview-icon.png
new file mode 100644
index 0000000..59c7644
--- /dev/null
+++ b/docs/html/images/tools/as-preview-icon.png
Binary files differ
diff --git a/docs/html/images/tools/as-preview-nochrome.png b/docs/html/images/tools/as-preview-nochrome.png
new file mode 100644
index 0000000..1011e08
--- /dev/null
+++ b/docs/html/images/tools/as-preview-nochrome.png
Binary files differ
diff --git a/docs/html/images/tools/as-theme-db.png b/docs/html/images/tools/as-theme-db.png
new file mode 100644
index 0000000..beade0d
--- /dev/null
+++ b/docs/html/images/tools/as-theme-db.png
Binary files differ
diff --git a/docs/html/images/tools/as-theme-icon.png b/docs/html/images/tools/as-theme-icon.png
new file mode 100644
index 0000000..0e5fdf0
--- /dev/null
+++ b/docs/html/images/tools/as-theme-icon.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/adt-firstapp-setup.png b/docs/html/images/training/firstapp/adt-firstapp-setup.png
index bf95285..05e147d 100644
--- a/docs/html/images/training/firstapp/adt-firstapp-setup.png
+++ b/docs/html/images/training/firstapp/adt-firstapp-setup.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/adt-new-activity.png b/docs/html/images/training/firstapp/adt-new-activity.png
index c396793..2c32dcc 100644
--- a/docs/html/images/training/firstapp/adt-new-activity.png
+++ b/docs/html/images/training/firstapp/adt-new-activity.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/edittext_gravity.png b/docs/html/images/training/firstapp/edittext_gravity.png
index f78e676..bc4f7ee 100644
--- a/docs/html/images/training/firstapp/edittext_gravity.png
+++ b/docs/html/images/training/firstapp/edittext_gravity.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/edittext_wrap.png b/docs/html/images/training/firstapp/edittext_wrap.png
index 156776d..fe56731 100644
--- a/docs/html/images/training/firstapp/edittext_wrap.png
+++ b/docs/html/images/training/firstapp/edittext_wrap.png
Binary files differ
diff --git a/docs/html/images/training/firstapp/firstapp.png b/docs/html/images/training/firstapp/firstapp.png
index d69cd20..581e000 100644
--- a/docs/html/images/training/firstapp/firstapp.png
+++ b/docs/html/images/training/firstapp/firstapp.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 5d1788a..e901652 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -22,12 +22,13 @@
                       <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
                       <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
                         <div id="ytapiplayer">
-                          <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+                          <a href="http://www.youtube.com/watch?v=i2uvYI6blEE"><img width=600 
+                          src="https://i1.ytimg.com/vi/i2uvYI6blEE/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
                         </div>
                         <script type="text/javascript">
                             var params = { allowScriptAccess: "always" };
                             var atts = { id: "ytapiplayer" };
-                            swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+                            swfobject.embedSWF("//www.youtube.com/v/i2uvYI6blEE?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
                               "ytapiplayer", "600", "336", "8", null, null, params, atts);
 
                             // Callback used to pause/resume carousel based on video state
@@ -56,9 +57,8 @@
                       </div>
                     </div>
                     <div class="content-right col-4">
-                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
-                    <p>Game developer Kiwi has had five titles in the top 25 grossing on Google Play. Hear how Google Play
-                      has helped them double revenue every six months.</p>
+                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Box Inc.</h1>
+                    <p>Box is a cloud-based platform and app for users to share business information. See how they got over 5 million downloads by leveraging the flexibility in the Android platform.</p>
                       <p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p>
                     </div>
                 </li>
diff --git a/docs/html/sdk/installing/studio-layout.jd b/docs/html/sdk/installing/studio-layout.jd
new file mode 100644
index 0000000..f0e5d59
--- /dev/null
+++ b/docs/html/sdk/installing/studio-layout.jd
@@ -0,0 +1,148 @@
+page.title=Using the Layout Editor
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>See also</h2>
+<ul>
+<li><a href="{@docRoot}sdk/installing/studio.html">
+Getting Started with Android Studio</a></li>
+<li><a href="{@docRoot}sdk/installing/studio-tips.html">
+Android Studio Tips and Tricks</a></li>
+<li><a href="{@docRoot}sdk/installing/migrate.html">
+Migrating from Eclipse</a></li>
+</div>
+</div>
+
+<a class="notice-developers-video"
+href="https://developers.google.com/events/io/sessions/324603352">
+<div>
+    <h3>Video</h3>
+    <p>What's New in Android Developer Tools</p>
+</div>
+</a>
+
+<p>Android Studio offers an advanced layout editor that allows you to drag-and-drop widgets
+into your layout and preview your layout while editing the XML.</p>
+
+<p>Within the layout editor, you can switch between the <strong>Text</strong> view, where
+you edit the XML file as text, and the <strong>Design</strong> view. Just click the
+appropriate tab at the bottom of the window to display the desired editor.</p>
+
+<h2>Editing in the Text View</h2>
+
+<p>You can use the <strong>Text</strong> view to edit your layout file. This section describes
+some of the features that are available in the <strong>Text</strong> view.</p>
+
+<h3>Preview</h3>
+
+<p>While editing in the <strong>Text</strong> view, you can preview the layout on devices
+by opening the <strong>Preview</strong> pane available on the right side of the window.
+Within the <strong>Preview</strong> pane, you can modify the preview by changing various
+options at the top of the pane, including the preview device, layout theme, platform
+version and more. To see a preview of how your app would look with a particular device
+skin, click the preview icon
+<img src="{@docRoot}images/tools/as-preview-icon.png" style="vertical-align:bottom;margin:0;height:19px" />
+and choose the desired device, such as Nexus 4:</p>
+
+<img src="{@docRoot}images/tools/as-preview-chrome.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> Previewing your app.</p>
+
+<p>To preview the layout on multiple devices simultaneously, select <strong>Preview All
+Screen Sizes</strong> from the device drop-down. </p>
+
+<p>When you click in the preview image, the layout editor highlights the corresponding
+section in the XML, and vice-versa.</p>
+
+<h3>Interactive error detection and recovery</h3>
+
+<p>As you edit the <strong>Text</strong> view of your layout XML file, Android Studio flags
+typos and offers assistance.</p>
+
+<p>For example, suppose you are adding a button, and you misspell it as &quot;Buttonn&quot;.
+Android Studio helps you to correct it by displaying an error such as the following,
+where you can click on &quot;Change to Button&quot; to fix the error in the XML file:</p>
+
+<img src="{@docRoot}images/tools/as-error.png" alt="" />
+
+<p class="img-caption"><strong>Figure 2.</strong> Flagging errors.</p>
+
+<p>Android Studio also prompts you to supply missing information. For example, suppose you
+start adding a fragment to your layout XML file. First of all, Android Studio displays
+auto-complete suggestions as you type. Once it becomes clear that you are adding a fragment,
+Android Studio displays an error panel with links that you can click to supply the missing
+attributes. Clicking &quot;Automatically add all missing attributes&quot; in this case
+does just that&mdash;it completes the fragment definition in your layout XML file:</p>
+
+<img src="{@docRoot}images/tools/as-frag-ex.png" alt="" />
+
+<p class="img-caption"><strong>Figure 3.</strong> Supplying missing information</p>
+
+<h3>Picking a theme</h3>
+
+<p>To pick a theme for your app, click the Theme icon
+<img src="{@docRoot}images/tools/as-theme-icon.png" style="vertical-align:bottom;margin:0;height:19px" />.
+</p>
+
+<p>This displays the <strong>Select Theme</strong> dialog, where you can search for a
+particular theme and/or select one from the list on the right hand side. The theme you
+choose will be reflected in the previewed image.</p>
+
+<img src="{@docRoot}images/tools/as-theme-db.png" alt="" />
+
+<p class="img-caption"><strong>Figure 4.</strong> Specifying a theme.</p>
+
+<h3>Localization</h3>
+
+<p>Android Studio provides built-in localization support. When you click the
+localization icon
+<img src="{@docRoot}images/tools/as-i18n-icon.png" style="vertical-align:bottom;margin:0;height:19px" />,
+you can select a particular locale, add and edit translations, preview the locales your
+app supports (all locales or just a single locale), and preview right-to-left layout for
+languages that are RTL.</p>
+
+<p>See <a href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting
+Different Languages</a> for a description of how to support different locales in your app.</p>
+<p>For example, here is a preview of a &quot;Hello World&quot; app for the
+<img src="{@docRoot}images/tools/as-fr-icon.png" style="vertical-align:bottom;margin:0;height:19px" />
+locale:</p>
+
+<img src="{@docRoot}images/tools/as-fr-device.png" alt="" />
+<p class="img-caption"><strong>Figure 5.</strong> Previewing locales.</p>
+
+<h2>Editing in the Design View</h2>
+
+<p>You can switch to the graphical editor by clicking <strong>Design</strong> at the
+bottom of the window. While editing in the <strong>Design</strong> view, you can show and
+hide the widgets available to drag-and-drop by clicking <strong>Palette</strong> on the
+left side of the window. Clicking <strong>Designer</strong> on the right side of the
+window reveals a panel with a layout hierarchy and a list of properties for each view in
+the layout.</p>
+
+<p>When you drag a widget into the graphical layout for your app, the display changes to
+help you place the widget. What you see depends on the type of layout. For example, if
+you're dragging a widget into a {@link android.widget.FrameLayout}, it displays a grid to
+help you place the widget, as shown in figure 6:</p>
+
+<img src="{@docRoot}images/tools/as-grid-layout.png" alt="" />
+
+<p class="img-caption"><strong>Figure 6.</strong> Using the grid layout to place a widget.</p>
+
+<p>Within the graphical editor, you can rearrange your app's UI by dragging widgets to
+the desired location.</p>
+
+<h3>Taking a snapshot</h3>
+
+<p>When you run your app on a connected device, you can take a snapshot of it by clicking
+the camera icon
+<img src="{@docRoot}images/tools/as-camera-icon.png" style="vertical-align:bottom;margin:0;height:19px" />
+to the left of the logging
+panel (at the bottom of the window by default). This takes a snapshot of your running app
+(or whatever is currently displayed on your device) and displays it in a window. Check
+<strong>Frame Screenshot</strong> to show your screenshot within the device skin of your
+choice. You can also specify whether you want the image to have screen glare and/or a drop
+shadow. Once you have the desired effect, you can save the image.</p>
+
+<p>You can use the same process to create a snapshot of your app's preview. Just click the
+camera icon in the preview area and follow the steps for adding a device skin.</p>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 5a7e270..feb7a6e 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -318,6 +318,12 @@
 
 
 <h2 id="Installing">Installing Android Studio</h2>
+<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you 
+have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
+If JDK is not available or the version is lower than 6,
+<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">download
+JDK from here</a>.</p>
+<p>To install Android Studio:</p>
 <ol>
 <li>Download the <strong>Android Studio</strong> package from above.</li>
 <li>Install Android Studio and the SDK tools:
diff --git a/docs/html/tools/help/logcat.jd b/docs/html/tools/help/logcat.jd
index ede1905..b30971e 100644
--- a/docs/html/tools/help/logcat.jd
+++ b/docs/html/tools/help/logcat.jd
@@ -45,7 +45,7 @@
     <tr>
       <td><code>-b&nbsp;&lt;buffer&gt;</code></td>
 
-      <td>Loads an alternate log buffer for viewing, such as <code>event</code> or
+      <td>Loads an alternate log buffer for viewing, such as <code>events</code> or
       <code>radio</code>. The <code>main</code> buffer is used by default. See <a href= 
       "{@docRoot}tools/debugging/debugging-log.html#alternativeBuffers">Viewing Alternative Log Buffers</a>.</td>
     </tr>
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index a8424e6..382165c 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -34,7 +34,9 @@
               Migrating from Eclipse</a></li>
           <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
               Tips and Tricks</a></li>
-        </ul>
+          <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
+              Using the Layout Editor</a></li>
+          </ul>
       </li>
       <li><a href="<?cs var:toroot ?>sdk/exploring.html">
           <span class="en">Exploring the SDK</span></a></li>
diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
index 2615bee..179b3ac 100644
--- a/docs/html/training/basics/firstapp/building-ui.jd
+++ b/docs/html/training/basics/firstapp/building-ui.jd
@@ -75,16 +75,16 @@
 
 <h2 id="LinearLayout">Create a Linear Layout</h2>
 
-<p>Open the <code>activity_main.xml</code> file from the <code>res/layout/</code>
+<p>Open the <code>fragment_main.xml</code> file from the <code>res/layout/</code>
 directory.</p>
 
 <p class="note"><strong>Note:</strong> In Eclipse, when you open a layout file, you’re first shown
 the Graphical Layout editor. This is an editor that helps you build layouts using WYSIWYG tools. For this
-lesson, you’re going to work directly with the XML, so click the <em>activity_main.xml</em> tab at
+lesson, you’re going to work directly with the XML, so click the <em>fragment_main.xml</em> tab at
 the bottom of the screen to open the XML editor.</p>
 
 <p>The BlankActivity template you chose when you created this project includes the
-<code>activity_main.xml</code> file with a {@link
+<code>fragment_main.xml</code> file with a {@link
 android.widget.RelativeLayout} root view and a {@link android.widget.TextView} child view.</p>
 
 <p>First, delete the {@link android.widget.TextView &lt;TextView>} element and change the {@link
@@ -95,7 +95,6 @@
 The result looks like this:</p>
 
 <pre>
-&lt;?xml version="1.0" encoding="utf-8"?>
 &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 9516e37..50485db 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -120,8 +120,8 @@
     <strong>Finish</strong>.</li>
 </ol>
 
-<p>Your Android project is now set up with some default files and you’re ready to begin
-building the app. Continue to the <a href="running-app.html">next lesson</a>.</p>
+<p>Your Android project is now a basic "Hello World" app that contains some default files. 
+To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
 
 
 
@@ -155,8 +155,8 @@
 projects.</p></li>
 </ol>
 
-<p>Your Android project is now set up with several default configurations and you’re ready to begin
-building the app. Continue to the <a href="running-app.html">next lesson</a>.</p>
+<p>Your Android project is now a basic "Hello World" app that contains some default files. 
+To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
 
 <p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the
 <code>tools/</code> directory to your <code>PATH</code> environment variable.</p>
diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd
index 999d399..23cedba 100644
--- a/docs/html/training/basics/firstapp/running-app.jd
+++ b/docs/html/training/basics/firstapp/running-app.jd
@@ -62,7 +62,7 @@
 attributes. For your first app, it should look like this:</p>
 <pre>
 &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
-    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />
+    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" />
     ...
 &lt;/manifest>
 </pre>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 712eabc..9aa25a3 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -45,7 +45,7 @@
 
 <h2 id="RespondToButton">Respond to the Send Button</h2>
 
-<p>To respond to the button's on-click event, open the <code>activity_main.xml</code>
+<p>To respond to the button's on-click event, open the <code>fragment_main.xml</code>
 layout file and add the <a
 href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>
 attribute to the {@link android.widget.Button &lt;Button>} element:</p>
@@ -73,14 +73,6 @@
 }
 </pre>
 
-<p>This requires that you import the {@link android.view.View} class:</p>
-<pre>
-import android.view.View;
-</pre>
-
-<p class="note"><strong>Tip:</strong> In Eclipse, press Ctrl + Shift + O to import missing classes
-(Cmd + Shift + O on Mac).</p>
-
 <p>In order for the system to match this method to the method name given to <a
 href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>,
 the signature must be exactly as shown. Specifically, the method must:</p>
@@ -111,6 +103,14 @@
 Intent intent = new Intent(this, DisplayMessageActivity.class);
 </pre>
 
+<p>This requires that you import the {@link android.content.Intent} class:</p>
+<pre>
+import android.content.Intent;
+</pre>
+
+<p class="note"><strong>Tip:</strong> In Eclipse, press Ctrl + Shift + O to import missing classes
+(Cmd + Shift + O on Mac).</p>
+
 <p>The constructor used here takes two parameters:</p>
 <ul>
   <li>A {@link
@@ -151,9 +151,8 @@
 </pre>
 
 <p class="note"><strong>Note:</strong>
-You now need import statements for <code>android.content.Intent</code>
-and <code>android.widget.EditText</code>. You'll define the <code>EXTRA_MESSAGE</code>
-constant in a moment.</p>
+You now need an import statement for <code>android.widget.EditText</code>. 
+You'll define the <code>EXTRA_MESSAGE</code> constant in a moment.</p>
 
 <p>An {@link android.content.Intent} can carry a collection of various data types as key-value
 pairs called <em>extras</em>. The {@link android.content.Intent#putExtra putExtra()} method takes the
@@ -165,7 +164,7 @@
 MainActivity} class:</p>
 
 <pre>
-public class MainActivity extends Activity {
+public class MainActivity extends ActionBarActivity {
     public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
     ...
 }
@@ -223,6 +222,7 @@
       <li><strong>Project</strong>: MyFirstApp</li>
       <li><strong>Activity Name</strong>: DisplayMessageActivity</li>
       <li><strong>Layout Name</strong>: activity_display_message</li>
+      <li><strong>Fragment Layout Name</strong>: fragment_display_message</li>
       <li><strong>Title</strong>: My Message</li>
       <li><strong>Hierarchial Parent</strong>: com.example.myfirstapp.MainActivity</li>
       <li><strong>Navigation Type</strong>: None</li>
@@ -240,49 +240,65 @@
 <ul>
   <li>The class
 already includes an implementation of the required {@link android.app.Activity#onCreate onCreate()}
-method.</li>
+method. You will update the implementation of this method later.</li>
   <li>There's also an implementation of the {@link android.app.Activity#onCreateOptionsMenu
 onCreateOptionsMenu()} method, but
 you won't need it for this app so you can remove it.</li>
   <li>There's also an implementation of {@link android.app.Activity#onOptionsItemSelected
   onOptionsItemSelected()} which handles the behavior for the action bar's <em>Up</em> behavior.
   Keep this one the way it is.</li>
+  <li>There's also a <code>PlaceholderFragment</code> class that extends 
+{@link android.app.Fragment}. You will not need this class in the final version of this
+activity.</li>
 </ul>
 
-<p>Because the {@link android.app.ActionBar} APIs are available only on {@link
-android.os.Build.VERSION_CODES#HONEYCOMB} (API level 11) and higher, you must add a condition
-around the {@link android.app.Activity#getActionBar()} method to check the current platform version.
-Additionally, you must add the {@code &#64;SuppressLint("NewApi")} tag to the
-{@link android.app.Activity#onCreate onCreate()} method to avoid <a
-href="{@docRoot}tools/help/lint.html">lint</a> errors.</p>
+<p>Fragments decompose application functionality and UI into reusable modules. For more 
+information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments 
+API Guide</a>. The final version of this activity does not use fragments.</p>
 
 <p>The {@code DisplayMessageActivity} class should now look like this:</p>
 
 <pre>
-public class DisplayMessageActivity extends Activity {
+public class DisplayMessageActivity extends ActionBarActivity {
 
-    &#64;SuppressLint("NewApi")
     &#64;Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_display_message);
 
-        // Make sure we're running on Honeycomb or higher to use ActionBar APIs
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-            // Show the Up button in the action bar.
-            getActionBar().setDisplayHomeAsUpEnabled(true);
+        if (savedInstanceState == null) {
+            getSupportFragmentManager().beginTransaction()
+                .add(R.id.container, new PlaceholderFragment()).commit();
         }
     }
 
     &#64;Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-        case android.R.id.home:
-            NavUtils.navigateUpFromSameTask(this);
+        // Handle action bar item clicks here. The action bar will
+        // automatically handle clicks on the Home/Up button, so long
+        // as you specify a parent activity in AndroidManifest.xml.
+        int id = item.getItemId();
+        if (id == R.id.action_settings) {
             return true;
         }
         return super.onOptionsItemSelected(item);
     }
+
+    /**
+     * A placeholder fragment containing a simple view.
+     */
+    public static class PlaceholderFragment extends Fragment {
+
+        public PlaceholderFragment() { }
+
+        &#64;Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                  Bundle savedInstanceState) {
+              View rootView = inflater.inflate(R.layout.fragment_display_message,
+                      container, false);
+              return rootView;
+        }
+    }
 }
 </pre>
 
@@ -422,7 +438,7 @@
 
 <img src="{@docRoot}images/training/firstapp/firstapp.png" />
 <p class="img-caption"><strong>Figure 2.</strong> Both activities in the final app, running
-on Android 4.0.
+on Android 4.4.
 
 <p>That's it, you've built your first Android app!</p>
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Console.java b/packages/SystemUI/src/com/android/systemui/recents/Console.java
index b3d9ccf..db95193 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Console.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Console.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents;
 
 
+import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -36,20 +37,20 @@
 
     /** Logs a key */
     public static void log(String key) {
-        Console.log(true, key, "", AnsiReset);
+        log(true, key, "", AnsiReset);
     }
 
     /** Logs a conditioned key */
     public static void log(boolean condition, String key) {
         if (condition) {
-            Console.log(condition, key, "", AnsiReset);
+            log(condition, key, "", AnsiReset);
         }
     }
 
     /** Logs a key in a specific color */
     public static void log(boolean condition, String key, Object data) {
         if (condition) {
-            Console.log(condition, key, data, AnsiReset);
+            log(condition, key, data, AnsiReset);
         }
     }
 
@@ -74,6 +75,50 @@
         }
     }
 
+    /** Logs a stack trace */
+    public static void logStackTrace() {
+        logStackTrace("", 99);
+    }
+
+    /** Logs a stack trace to a certain depth */
+    public static void logStackTrace(int depth) {
+        logStackTrace("", depth);
+    }
+
+    /** Logs a stack trace to a certain depth with a key */
+    public static void logStackTrace(String key, int depth) {
+        int offset = 0;
+        StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+        String tinyStackTrace = "";
+        // Skip over the known stack trace classes
+        for (int i = 0; i < callStack.length; i++) {
+            StackTraceElement el = callStack[i];
+            String className = el.getClassName();
+            if (className.indexOf("dalvik.system.VMStack") == -1 &&
+                className.indexOf("java.lang.Thread") == -1 &&
+                className.indexOf("recents.Console") == -1) {
+                break;
+            } else {
+                offset++;
+            }
+        }
+        // Build the pretty stack trace
+        int start = Math.min(offset + depth, callStack.length);
+        int end = offset;
+        String indent = "";
+        for (int i = start - 1; i >= end; i--) {
+            StackTraceElement el = callStack[i];
+            tinyStackTrace += indent + " -> " + el.getClassName() +
+                    "[" + el.getLineNumber() + "]." + el.getMethodName();
+            if (i > end) {
+                tinyStackTrace += "\n";
+                indent += "  ";
+            }
+        }
+        log(true, key, tinyStackTrace, AnsiRed);
+    }
+
+
     /** Returns the stringified MotionEvent action */
     public static String motionEventActionToString(int action) {
         switch (action) {
@@ -93,4 +138,25 @@
                 return "" + action;
         }
     }
+
+    public static String trimMemoryLevelToString(int level) {
+        switch (level) {
+            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
+                return "UI Hidden";
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
+                return "Running Moderate";
+            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
+                return "Background";
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
+                return "Running Low";
+            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+                return "Moderate";
+            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
+                return "Critical";
+            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+                return "Complete";
+            default:
+                return "" + level;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index aeae4ab..57ebbc2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -30,9 +30,11 @@
             public static final boolean EnableTaskStackClipping = false;
             public static final boolean EnableBackgroundTaskLoading = true;
             public static final boolean ForceDisableBackgroundCache = false;
+
             public static final boolean TaskDataLoader = false;
             public static final boolean SystemUIHandshake = false;
             public static final boolean TimeSystemCalls = false;
+            public static final boolean Memory = false;
         }
 
         public static class UI {
@@ -41,7 +43,7 @@
             public static final boolean TouchEvents = false;
             public static final boolean MeasureAndLayout = false;
             public static final boolean Clipping = false;
-            public static final boolean HwLayers = true;
+            public static final boolean HwLayers = false;
         }
 
         public static class TaskStack {
@@ -55,13 +57,16 @@
 
     public static class Values {
         public static class Window {
+            // The dark background dim is set behind the empty recents view
             public static final float DarkBackgroundDim = 0.5f;
+            // The background dim is set behind the card stack
             public static final float BackgroundDim = 0.35f;
         }
 
         public static class RecentsTaskLoader {
             // XXX: This should be calculated on the first load
             public static final int PreloadFirstTasksCount = 5;
+            // For debugging, this allows us to multiply the number of cards for each task
             public static final int TaskEntryMultiplier = 1;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d050847..fc4d819 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -23,6 +23,7 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
+import com.android.systemui.recent.RecentTasksLoader;
 import com.android.systemui.recents.model.SpaceNode;
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.RecentsView;
@@ -168,6 +169,14 @@
     }
 
     @Override
+    public void onTrimMemory(int level) {
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        if (loader != null) {
+            loader.onTrimMemory(level);
+        }
+    }
+
+    @Override
     public void onBackPressed() {
         if (!mRecentsView.unfilterFilteredStacks()) {
             super.onBackPressed();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index f3881ae..ed981ed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -30,7 +30,6 @@
 
     DisplayMetrics mDisplayMetrics;
 
-    public boolean layoutVerticalStack;
     public Rect systemInsets = new Rect();
 
     /** Private constructor */
@@ -56,7 +55,6 @@
 
         boolean isPortrait = context.getResources().getConfiguration().orientation ==
                 Configuration.ORIENTATION_PORTRAIT;
-        layoutVerticalStack = isPortrait || Constants.LANDSCAPE_LAYOUT_VERTICAL_STACK;
     }
 
     public void updateSystemInsets(Rect insets) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 522ab0f..13a3424 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -57,8 +57,9 @@
                     tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top);
                     tsv.boundScroll();
                     TaskViewTransform transform = tsv.getStackTransform(0);
+                    Rect taskRect = new Rect(transform.rect);
 
-                    data.putParcelable("taskRect", transform.rect);
+                    data.putParcelable("taskRect", taskRect);
                     Message reply = Message.obtain(null, MSG_UPDATE_RECENTS_FOR_CONFIGURATION, 0, 0);
                     reply.setData(data);
                     msg.replyTo.send(reply);
@@ -100,4 +101,12 @@
         Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onDestroy]");
         super.onDestroy();
     }
+
+    @Override
+    public void onTrimMemory(int level) {
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        if (loader != null) {
+            loader.onTrimMemory(level);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index c303ca7..96efed4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents;
 
 import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -35,6 +36,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 
@@ -233,7 +235,7 @@
     @Override
     protected int sizeOf(Task t, Bitmap bitmap) {
         // The cache size will be measured in kilobytes rather than number of items
-        return bitmap.getByteCount() / 1024;
+        return bitmap.getAllocationByteCount() / 1024;
     }
 }
 
@@ -247,17 +249,28 @@
     TaskResourceLoadQueue mLoadQueue;
     TaskResourceLoader mLoader;
 
+    int mMaxThumbnailCacheSize;
+    int mMaxIconCacheSize;
+
     BitmapDrawable mDefaultIcon;
     Bitmap mDefaultThumbnail;
 
     /** Private Constructor */
     private RecentsTaskLoader(Context context) {
+        // Calculate the cache sizes
         int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
-        int iconCacheSize = Constants.DebugFlags.App.ForceDisableBackgroundCache ? 1 : maxMemory / 16;
-        int thumbnailCacheSize = Constants.DebugFlags.App.ForceDisableBackgroundCache ? 1 : maxMemory / 8;
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+        mMaxThumbnailCacheSize = maxMemory / 8;
+        mMaxIconCacheSize = mMaxThumbnailCacheSize / 4;
+        int iconCacheSize = Constants.DebugFlags.App.ForceDisableBackgroundCache ? 1 :
+                mMaxIconCacheSize;
+        int thumbnailCacheSize = Constants.DebugFlags.App.ForceDisableBackgroundCache ? 1 :
+                mMaxThumbnailCacheSize;
+
+        Console.log(Constants.DebugFlags.App.EnableBackgroundTaskLoading,
                 "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
                 " iconCache: " + iconCacheSize);
+
+        // Initialize the cache and loaders
         mLoadQueue = new TaskResourceLoadQueue();
         mIconCache = new DrawableLruCache(iconCacheSize);
         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
@@ -293,7 +306,7 @@
 
     /** Reload the set of recent tasks */
     SpaceNode reload(Context context, int preloadCount) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsTaskLoader|reload]");
+        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
         TaskStack stack = new TaskStack(context);
         SpaceNode root = new SpaceNode(context);
         root.setStack(stack);
@@ -310,7 +323,7 @@
             Console.log(Constants.DebugFlags.App.TimeSystemCalls,
                     "[RecentsTaskLoader|getRecentTasks]",
                     "" + (System.currentTimeMillis() - t1) + "ms");
-            Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+            Console.log(Constants.DebugFlags.App.TaskDataLoader,
                     "[RecentsTaskLoader|tasks]", "" + tasks.size());
 
             // Remove home/recents tasks
@@ -335,35 +348,51 @@
             int taskCount = tasks.size();
             for (int i = 0; i < taskCount; i++) {
                 ActivityManager.RecentTaskInfo t = tasks.get(i);
-
-                // Load the label, icon and thumbnail
                 ActivityInfo info = pm.getActivityInfo(t.baseIntent.getComponent(),
                         PackageManager.GET_META_DATA);
                 String title = info.loadLabel(pm).toString();
-                Drawable icon = null;
-                Bitmap thumbnail = null;
                 Task task;
-                if (i >= (taskCount - preloadCount) || !Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
-                    Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+                // Preload the specified number of apps
+                if (i >= (taskCount - preloadCount) ||
+                        !Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
+                    Console.log(Constants.DebugFlags.App.TaskDataLoader,
                             "[RecentsTaskLoader|preloadTask]",
                             "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
-                    icon = info.loadIcon(pm);
-                    thumbnail = am.getTaskTopThumbnail(t.id);
-                    for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) {
-                        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
-                                "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
-                        task = new Task(t.persistentId, t.baseIntent, title, icon, thumbnail);
+
+                    task = new Task(t.persistentId, t.baseIntent, title, null, null);
+
+                    // Load the icon (if possible from the cache)
+                    if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
+                        task.icon = mIconCache.get(task);
+                    }
+                    if (task.icon == null) {
+                        task.icon = info.loadIcon(pm);
                         if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
-                            if (thumbnail != null) mThumbnailCache.put(task, thumbnail);
-                            if (icon != null) {
-                                mIconCache.put(task, icon);
-                            }
+                            mIconCache.put(task, task.icon);
                         }
+                    }
+
+                    // Load the thumbnail (if possible from the cache)
+                    if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
+                        task.thumbnail = mThumbnailCache.get(task);
+                    }
+                    if (task.thumbnail == null) {
+                        task.thumbnail = am.getTaskTopThumbnail(t.id);
+                        if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
+                            mThumbnailCache.put(task, task.thumbnail);
+                        }
+                    }
+
+                    // Create as many tasks a we want to multiply by
+                    for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) {
+                        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                                "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
                         stack.addTask(task);
                     }
                 } else {
+                    // Create as many tasks a we want to multiply by
                     for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) {
-                        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+                        Console.log(Constants.DebugFlags.App.TaskDataLoader,
                                 "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
                         task = new Task(t.persistentId, t.baseIntent, title, null, null);
                         stack.addTask(task);
@@ -388,9 +417,9 @@
             t1 = System.currentTimeMillis();
             List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
             Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
-            Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsTaskLoader|stacks]", "" + tasks.size());
+            Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
             for (ActivityManager.StackInfo s : stackInfos) {
-                Console.log(Constants.DebugFlags.App.SystemUIHandshake, "  [RecentsTaskLoader|stack]", s.toString());
+                Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [RecentsTaskLoader|stack]", s.toString());
                 if (stacks.containsKey(s.stackId)) {
                     stacks.get(s.stackId).setRect(s.bounds);
                 }
@@ -403,45 +432,46 @@
         return root;
     }
 
-    /** Acquires the task resource data from the pool.
-     * XXX: Move this into Task? */
+    /** Acquires the task resource data from the pool. */
     public void loadTaskData(Task t) {
         if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
-            t.icon = mIconCache.get(t);
-            t.thumbnail = mThumbnailCache.get(t);
+            Drawable icon = mIconCache.get(t);
+            Bitmap thumbnail = mThumbnailCache.get(t);
 
             Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
-                    t + " icon: " + t.icon + " thumbnail: " + t.thumbnail);
+                    t + " icon: " + icon + " thumbnail: " + thumbnail +
+                            " thumbnailCacheSize: " + mThumbnailCache.size());
 
             boolean requiresLoad = false;
-            if (t.icon == null) {
-                t.icon = mDefaultIcon;
+            if (icon == null) {
+                icon = mDefaultIcon;
                 requiresLoad = true;
             }
-            if (t.thumbnail == null) {
-                t.thumbnail = mDefaultThumbnail;
+            if (thumbnail == null) {
+                thumbnail = mDefaultThumbnail;
                 requiresLoad = true;
             }
             if (requiresLoad) {
                 mLoadQueue.addTask(t);
             }
+            t.notifyTaskLoaded(thumbnail, icon);
         }
     }
 
-    /** Releases the task resource data back into the pool.
-     * XXX: Move this into Task? */
+    /** Releases the task resource data back into the pool. */
     public void unloadTaskData(Task t) {
         if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
             Console.log(Constants.DebugFlags.App.TaskDataLoader,
-                    "[RecentsTaskLoader|unloadTask]", t);
+                    "[RecentsTaskLoader|unloadTask]", t +
+                    " thumbnailCacheSize: " + mThumbnailCache.size());
             mLoadQueue.removeTask(t);
-            t.icon = mDefaultIcon;
-            t.thumbnail = mDefaultThumbnail;
+            t.notifyTaskUnloaded(mDefaultThumbnail, mDefaultIcon);
+        } else {
+            t.notifyTaskUnloaded(null, null);
         }
     }
 
-    /** Completely removes the resource data from the pool.
-     * XXX: Move this into Task? */
+    /** Completely removes the resource data from the pool. */
     public void deleteTaskData(Task t) {
         if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
             Console.log(Constants.DebugFlags.App.TaskDataLoader,
@@ -449,9 +479,10 @@
             mLoadQueue.removeTask(t);
             mThumbnailCache.remove(t);
             mIconCache.remove(t);
+            t.notifyTaskUnloaded(mDefaultThumbnail, mDefaultIcon);
+        } else {
+            t.notifyTaskUnloaded(null, null);
         }
-        t.icon = mDefaultIcon;
-        t.thumbnail = mDefaultThumbnail;
     }
 
     /** Stops the task loader */
@@ -460,4 +491,51 @@
         mLoader.stop();
         mLoadQueue.clearTasks();
     }
+
+    void onTrimMemory(int level) {
+        Console.log(Constants.DebugFlags.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
+                Console.trimMemoryLevelToString(level));
+
+        if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) {
+            // If we are hidden, then we should unload each of the task keys
+            if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
+                Console.log(Constants.DebugFlags.App.Memory, "[RecentsTaskLoader|unloadTasks]"
+                );
+                // Unload each of the keys in the thumbnail cache
+                Map<Task, Bitmap> thumbnailCache = mThumbnailCache.snapshot();
+                for (Task t : thumbnailCache.keySet()) {
+                    unloadTaskData(t);
+                }
+                // As well as the keys in the icon cache
+                Map<Task, Drawable> iconCache = mIconCache.snapshot();
+                for (Task t : iconCache.keySet()) {
+                    unloadTaskData(t);
+                }
+            }
+
+            switch (level) {
+                case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
+                case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
+                case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
+                    // We are leaving recents, so trim the data a bit
+                    mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 2);
+                    mIconCache.trimToSize(mMaxIconCacheSize / 2);
+                    break;
+                case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
+                case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+                    // We are going to be low on memory
+                    mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 4);
+                    mIconCache.trimToSize(mMaxIconCacheSize / 4);
+                    break;
+                case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
+                case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+                    // We are low on memory, so release everything
+                    mThumbnailCache.evictAll();
+                    mIconCache.evictAll();
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 9b03c5d..378984c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -54,6 +54,24 @@
         }
     }
 
+    /** Notifies the callback listeners that this task has been loaded */
+    public void notifyTaskLoaded(Bitmap thumbnail, Drawable icon) {
+        this.icon = icon;
+        this.thumbnail = thumbnail;
+        if (mCb != null) {
+            mCb.onTaskBound();
+        }
+    }
+
+    /** Notifies the callback listeners that this task has been unloaded */
+    public void notifyTaskUnloaded(Bitmap defaultThumbnail, Drawable defaultIcon) {
+        icon = defaultIcon;
+        thumbnail = defaultThumbnail;
+        if (mCb != null) {
+            mCb.onTaskUnbound();
+        }
+    }
+
     @Override
     public boolean equals(Object o) {
         // If we have multiple task entries for the same task, then we do the simple object
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskCallbacks.java
index 169f56c..712580d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskCallbacks.java
@@ -20,4 +20,8 @@
 public interface TaskCallbacks {
     /* Notifies when a task's data has been updated */
     public void onTaskDataChanged(Task task);
+    /* Notifies when a task has been bound */
+    public void onTaskBound();
+    /* Notifies when a task has been unbound */
+    public void onTaskUnbound();
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index fe661bc..21ef9ff 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -28,6 +28,8 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.animation.LinearInterpolator;
+import com.android.systemui.recents.Console;
+import com.android.systemui.recents.Constants;
 
 /**
  * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
@@ -176,6 +178,9 @@
     }
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        Console.log(Constants.DebugFlags.UI.TouchEvents,
+                "[SwipeHelper|interceptTouchEvent]",
+                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
         final int action = ev.getAction();
 
         switch (action) {
@@ -200,7 +205,7 @@
                     if (Math.abs(delta) > mPagingTouchSlop) {
                         mCallback.onBeginDrag(mCurrView);
                         mDragging = true;
-                        mInitialTouchPos = getPos(ev) - getTranslation(mCurrView);
+                        mInitialTouchPos = pos - getTranslation(mCurrView);
                     }
                 }
                 break;
@@ -286,6 +291,10 @@
     }
 
     public boolean onTouchEvent(MotionEvent ev) {
+        Console.log(Constants.DebugFlags.UI.TouchEvents,
+                "[SwipeHelper|touchEvent]",
+                Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
+
         if (!mDragging) {
             if (!onInterceptTouchEvent(ev)) {
                 return mCanCurrViewBeDimissed;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 9dd6c0b..7753d69 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -435,19 +435,12 @@
         mStackRectSansPeek.top += Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
 
         // Compute the task rect
-        if (RecentsConfiguration.getInstance().layoutVerticalStack) {
-            int minHeight = (int) (mStackRect.height() -
-                    (Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height()));
-            int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height()));
-            int centerX = mStackRect.centerX();
-            mTaskRect.set(centerX - size / 2, mStackRectSansPeek.top,
-                    centerX + size / 2, mStackRectSansPeek.top + size);
-        } else {
-            int size = Math.min(mStackRect.width(), mStackRect.height());
-            int centerY = mStackRect.centerY();
-            mTaskRect.set(mStackRectSansPeek.top, centerY - size / 2,
-                    mStackRectSansPeek.top + size, centerY + size / 2);
-        }
+        int minHeight = (int) (mStackRect.height() -
+                (Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height()));
+        int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height()));
+        int centerX = mStackRect.centerX();
+        mTaskRect.set(centerX - size / 2, mStackRectSansPeek.top,
+                centerX + size / 2, mStackRectSansPeek.top + size);
 
         // Update the scroll bounds
         updateMinMaxScroll(false);
@@ -589,7 +582,6 @@
         // Report that this tasks's data is no longer being used
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         loader.unloadTaskData(task);
-        tv.unbindFromTask();
 
         // Detach the view from the hierarchy
         detachViewFromParent(tv);
@@ -610,7 +602,6 @@
         // Request that this tasks's data be filled
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         loader.loadTaskData(task);
-        tv.syncToTask();
 
         // Find the index where this task should be placed in the children
         int insertIndex = -1;
@@ -678,14 +669,13 @@
 }
 
 /* Handles touch events */
-class TaskStackViewTouchHandler {
+class TaskStackViewTouchHandler implements SwipeHelper.Callback {
     static int INACTIVE_POINTER_ID = -1;
 
     TaskStackView mSv;
     VelocityTracker mVelocityTracker;
 
     boolean mIsScrolling;
-    boolean mIsSwiping;
 
     int mInitialMotionX, mInitialMotionY;
     int mLastMotionX, mLastMotionY;
@@ -697,21 +687,24 @@
     int mMaximumVelocity;
     // The scroll touch slop is used to calculate when we start scrolling
     int mScrollTouchSlop;
-    // The swipe touch slop is used to calculate when we start swiping left/right, this takes
-    // precendence over the scroll touch slop in case the user makes a gesture that starts scrolling
-    // but is intended to be a swipe
-    int mSwipeTouchSlop;
-    // After a certain amount of scrolling, we should start ignoring checks for swiping
-    int mMaxScrollMotionToRejectSwipe;
+    // The page touch slop is used to calculate when we start swiping
+    float mPagingTouchSlop;
+
+    SwipeHelper mSwipeHelper;
+    boolean mInterceptedBySwipeHelper;
 
     public TaskStackViewTouchHandler(Context context, TaskStackView sv) {
         ViewConfiguration configuration = ViewConfiguration.get(context);
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mScrollTouchSlop = configuration.getScaledTouchSlop();
-        mSwipeTouchSlop = 2 * mScrollTouchSlop;
-        mMaxScrollMotionToRejectSwipe = 4 * mScrollTouchSlop;
+        mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
         mSv = sv;
+
+
+        float densityScale = context.getResources().getDisplayMetrics().density;
+        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop);
+        mSwipeHelper.setMinAlpha(1f);
     }
 
     /** Velocity tracker helpers */
@@ -754,11 +747,18 @@
                 "[TaskStackViewTouchHandler|interceptTouchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
+        // Return early if we have no children
         boolean hasChildren = (mSv.getChildCount() > 0);
         if (!hasChildren) {
             return false;
         }
 
+        // Pass through to swipe helper if we are swiping
+        mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev);
+        if (mInterceptedBySwipeHelper) {
+            return true;
+        }
+
         boolean wasScrolling = !mSv.mScroller.isFinished() ||
                 (mSv.mScrollAnimator != null && mSv.mScrollAnimator.isRunning());
         int action = ev.getAction();
@@ -777,7 +777,8 @@
                 mVelocityTracker.addMovement(ev);
                 // Check if the scroller is finished yet
                 mIsScrolling = !mSv.mScroller.isFinished();
-                mIsSwiping = false;
+                // Enable HW layers
+                mSv.addHwLayersRefCount();
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -786,25 +787,7 @@
                 int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                 int y = (int) ev.getY(activePointerIndex);
                 int x = (int) ev.getX(activePointerIndex);
-                if (mActiveTaskView != null &&
-                        mTotalScrollMotion < mMaxScrollMotionToRejectSwipe &&
-                        Math.abs(x - mInitialMotionX) > Math.abs(y - mInitialMotionY) &&
-                        Math.abs(x - mInitialMotionX) > mSwipeTouchSlop) {
-                    // Start swiping and stop scrolling
-                    mIsScrolling = false;
-                    mIsSwiping = true;
-                    System.out.println("SWIPING: " + mActiveTaskView);
-                    // Initialize the velocity tracker if necessary
-                    initOrResetVelocityTracker();
-                    mVelocityTracker.addMovement(ev);
-                    // Disallow parents from intercepting touch events
-                    final ViewParent parent = mSv.getParent();
-                    if (parent != null) {
-                        parent.requestDisallowInterceptTouchEvent(true);
-                    }
-                    // Enable HW layers
-                    mSv.addHwLayersRefCount();
-                } else if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) {
+                if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) {
                     // Save the touch move info
                     mIsScrolling = true;
                     // Initialize the velocity tracker if necessary
@@ -815,8 +798,6 @@
                     if (parent != null) {
                         parent.requestDisallowInterceptTouchEvent(true);
                     }
-                    // Enable HW layers
-                    mSv.addHwLayersRefCount();
                 }
 
                 mLastMotionX = x;
@@ -829,16 +810,17 @@
                 mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
                 // Reset the drag state and the velocity tracker
                 mIsScrolling = false;
-                mIsSwiping = false;
                 mActivePointerId = INACTIVE_POINTER_ID;
                 mActiveTaskView = null;
                 mTotalScrollMotion = 0;
                 recycleVelocityTracker();
+                // Disable HW layers
+                mSv.decHwLayersRefCount();
                 break;
             }
         }
 
-        return wasScrolling || mIsScrolling || mIsSwiping;
+        return wasScrolling || mIsScrolling;
     }
 
     /** Handles touch events once we have intercepted them */
@@ -853,6 +835,11 @@
             return false;
         }
 
+        // Pass through to swipe helper if we are swiping
+        if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) {
+            return true;
+        }
+
         // Update the velocity tracker
         initVelocityTrackerIfNotExists();
         mVelocityTracker.addMovement(ev);
@@ -871,7 +858,6 @@
                 // Initialize the velocity tracker
                 initOrResetVelocityTracker();
                 mVelocityTracker.addMovement(ev);
-                // XXX: Set mIsScrolling or mIsSwiping?
                 // Disallow parents from intercepting touch events
                 final ViewParent parent = mSv.getParent();
                 if (parent != null) {
@@ -886,28 +872,7 @@
                 int x = (int) ev.getX(activePointerIndex);
                 int y = (int) ev.getY(activePointerIndex);
                 int deltaY = mLastMotionY - y;
-                int deltaX = x - mLastMotionX;
-                if (!mIsSwiping) {
-                    if (mActiveTaskView != null &&
-                            mTotalScrollMotion < mMaxScrollMotionToRejectSwipe &&
-                            Math.abs(x - mInitialMotionX) > Math.abs(y - mInitialMotionY) &&
-                            Math.abs(x - mInitialMotionX) > mSwipeTouchSlop) {
-                        mIsScrolling = false;
-                        mIsSwiping = true;
-                        System.out.println("SWIPING: " + mActiveTaskView);
-                        // Initialize the velocity tracker if necessary
-                        initOrResetVelocityTracker();
-                        mVelocityTracker.addMovement(ev);
-                        // Disallow parents from intercepting touch events
-                        final ViewParent parent = mSv.getParent();
-                        if (parent != null) {
-                            parent.requestDisallowInterceptTouchEvent(true);
-                        }
-                        // Enable HW layers
-                        mSv.addHwLayersRefCount();
-                    }
-                }
-                if (!mIsSwiping && !mIsScrolling) {
+                if (!mIsScrolling) {
                     if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) {
                         mIsScrolling = true;
                         // Initialize the velocity tracker
@@ -927,8 +892,6 @@
                     if (mSv.isScrollOutOfBounds()) {
                         mVelocityTracker.clear();
                     }
-                } else if (mIsSwiping) {
-                    mActiveTaskView.setTranslationX(mActiveTaskView.getTranslationX() + deltaX);
                 }
                 mLastMotionX = x;
                 mLastMotionY = y;
@@ -936,107 +899,33 @@
                 break;
             }
             case MotionEvent.ACTION_UP: {
-                if (mIsScrolling || mIsSwiping) {
-                    final TaskView activeTv = mActiveTaskView;
-                    final VelocityTracker velocityTracker = mVelocityTracker;
-                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                final VelocityTracker velocityTracker = mVelocityTracker;
+                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                int velocity = (int) velocityTracker.getYVelocity(mActivePointerId);
 
-                    if (mIsSwiping) {
-                        int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);
-                        if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
-                            // Fling to dismiss
-                            int newScrollX = (int) (Math.signum(initialVelocity) *
-                                    activeTv.getMeasuredWidth());
-                            int duration = Math.min(Constants.Values.TaskStackView.Animation.SwipeDismissDuration,
-                                    (int) (Math.abs(newScrollX - activeTv.getScrollX()) *
-                                            1000f / Math.abs(initialVelocity)));
-                            activeTv.animate()
-                                    .translationX(newScrollX)
-                                    .alpha(0f)
-                                    .setDuration(duration)
-                                    .setListener(new AnimatorListenerAdapter() {
-                                        @Override
-                                        public void onAnimationEnd(Animator animation) {
-                                            Task task = activeTv.getTask();
-                                            Activity activity = (Activity) mSv.getContext();
-
-                                            // We have to disable the listener to ensure that we
-                                            // don't hit this again
-                                            activeTv.animate().setListener(null);
-
-                                            // Remove the task from the view
-                                            mSv.mStack.removeTask(task);
-
-                                            // Remove any stored data from the loader
-                                            RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-                                            loader.deleteTaskData(task);
-
-                                            // Remove the task from activity manager
-                                            final ActivityManager am = (ActivityManager)
-                                                activity.getSystemService(Context.ACTIVITY_SERVICE);
-                                            if (am != null) {
-                                                am.removeTask(activeTv.getTask().id,
-                                                        ActivityManager.REMOVE_TASK_KILL_PROCESS);
-                                            }
-
-                                            // If there are no remaining tasks, then just close the activity
-                                            if (mSv.mStack.getTaskCount() == 0) {
-                                                activity.finish();
-                                            }
-
-                                            // Disable HW layers
-                                            mSv.decHwLayersRefCount();
-                                        }
-                                    })
-                                    .start();
-                            // Enable HW layers
-                            mSv.addHwLayersRefCount();
-                        } else {
-                            // Animate it back into place
-                            // XXX: Make this animation a function of the velocity OR distance
-                            int duration = Constants.Values.TaskStackView.Animation.SwipeSnapBackDuration;
-                            activeTv.animate()
-                                    .translationX(0)
-                                    .setDuration(duration)
-                                    .setListener(new AnimatorListenerAdapter() {
-                                        @Override
-                                        public void onAnimationEnd(Animator animation) {
-                                            // Disable HW layers
-                                            mSv.decHwLayersRefCount();
-                                        }
-                                    })
-                                    .start();
-                            // Enable HW layers
-                            mSv.addHwLayersRefCount();
-                        }
-                    } else {
-                        int velocity = (int) velocityTracker.getYVelocity(mActivePointerId);
-                        if ((Math.abs(velocity) > mMinimumVelocity)) {
-                            Console.log(Constants.DebugFlags.UI.TouchEvents,
-                                "[TaskStackViewTouchHandler|fling]",
-                                "scroll: " + mSv.getStackScroll() + " velocity: " + velocity,
-                                    Console.AnsiGreen);
-                            // Enable HW layers on the stack
-                            mSv.addHwLayersRefCount();
-                            // Fling scroll
-                            mSv.mScroller.fling(0, mSv.getStackScroll(),
-                                    0, -velocity,
-                                    0, 0,
-                                    mSv.mMinScroll, mSv.mMaxScroll,
-                                    0, 0);
-                            // Invalidate to kick off computeScroll
-                            mSv.invalidate();
-                        } else if (mSv.isScrollOutOfBounds()) {
-                            // Animate the scroll back into bounds
-                            // XXX: Make this animation a function of the velocity OR distance
-                            mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
-                        }
-                    }
+                if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
+                    Console.log(Constants.DebugFlags.UI.TouchEvents,
+                        "[TaskStackViewTouchHandler|fling]",
+                        "scroll: " + mSv.getStackScroll() + " velocity: " + velocity,
+                            Console.AnsiGreen);
+                    // Enable HW layers on the stack
+                    mSv.addHwLayersRefCount();
+                    // Fling scroll
+                    mSv.mScroller.fling(0, mSv.getStackScroll(),
+                            0, -velocity,
+                            0, 0,
+                            mSv.mMinScroll, mSv.mMaxScroll,
+                            0, 0);
+                    // Invalidate to kick off computeScroll
+                    mSv.invalidate();
+                } else if (mSv.isScrollOutOfBounds()) {
+                    // Animate the scroll back into bounds
+                    // XXX: Make this animation a function of the velocity OR distance
+                    mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
                 }
 
                 mActivePointerId = INACTIVE_POINTER_ID;
                 mIsScrolling = false;
-                mIsSwiping = false;
                 mTotalScrollMotion = 0;
                 recycleVelocityTracker();
                 // Disable HW layers
@@ -1044,25 +933,14 @@
                 break;
             }
             case MotionEvent.ACTION_CANCEL: {
-                if (mIsScrolling || mIsSwiping) {
-                    if (mIsSwiping) {
-                        // Animate it back into place
-                        // XXX: Make this animation a function of the velocity OR distance
-                        int duration = Constants.Values.TaskStackView.Animation.SwipeSnapBackDuration;
-                        mActiveTaskView.animate()
-                                .translationX(0)
-                                .setDuration(duration)
-                                .start();
-                    } else {
-                        // Animate the scroll back into bounds
-                        // XXX: Make this animation a function of the velocity OR distance
-                        mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
-                    }
+                if (mSv.isScrollOutOfBounds()) {
+                    // Animate the scroll back into bounds
+                    // XXX: Make this animation a function of the velocity OR distance
+                    mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration);
                 }
 
                 mActivePointerId = INACTIVE_POINTER_ID;
                 mIsScrolling = false;
-                mIsSwiping = false;
                 mTotalScrollMotion = 0;
                 recycleVelocityTracker();
                 // Disable HW layers
@@ -1072,4 +950,72 @@
         }
         return true;
     }
+
+    /**** SwipeHelper Implementation ****/
+
+    @Override
+    public View getChildAtPosition(MotionEvent ev) {
+        return findViewAtPoint((int) ev.getX(), (int) ev.getY());
+    }
+
+    @Override
+    public boolean canChildBeDismissed(View v) {
+        return true;
+    }
+
+    @Override
+    public void onBeginDrag(View v) {
+        // Enable HW layers
+        mSv.addHwLayersRefCount();
+        // Disallow parents from intercepting touch events
+        final ViewParent parent = mSv.getParent();
+        if (parent != null) {
+            parent.requestDisallowInterceptTouchEvent(true);
+        }
+    }
+
+    @Override
+    public void onChildDismissed(View v) {
+        TaskView tv = (TaskView) v;
+        Task task = tv.getTask();
+        Activity activity = (Activity) mSv.getContext();
+
+        // We have to disable the listener to ensure that we
+        // don't hit this again
+        tv.animate().setListener(null);
+
+        // Remove the task from the view
+        mSv.mStack.removeTask(task);
+
+        // Remove any stored data from the loader
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        loader.deleteTaskData(task);
+
+        // Remove the task from activity manager
+        final ActivityManager am = (ActivityManager)
+                activity.getSystemService(Context.ACTIVITY_SERVICE);
+        if (am != null) {
+            am.removeTask(tv.getTask().id,
+                    ActivityManager.REMOVE_TASK_KILL_PROCESS);
+        }
+
+        // If there are no remaining tasks, then just close the activity
+        if (mSv.mStack.getTaskCount() == 0) {
+            activity.finish();
+        }
+
+        // Disable HW layers
+        mSv.decHwLayersRefCount();
+    }
+
+    @Override
+    public void onSnapBackCompleted(View v) {
+        // Do Nothing
+    }
+
+    @Override
+    public void onDragCancelled(View v) {
+        // Disable HW layers
+        mSv.decHwLayersRefCount();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index b1d0d13..9ef74ca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -255,13 +255,13 @@
     }
 
     /** Actually synchronizes the model data into the views */
-    void syncToTask() {
+    private void syncToTask() {
         mThumbnailView.rebindToTask(mTask, false);
         mIconView.rebindToTask(mTask, false);
     }
 
     /** Unset the task and callback */
-    void unbindFromTask() {
+    private void unbindFromTask() {
         mTask.setCallbacks(null);
         mThumbnailView.unbindFromTask();
         mIconView.unbindFromTask();
@@ -357,16 +357,16 @@
 
     /** Enable the hw layers on this task view */
     void enableHwLayers() {
-        Console.log(Constants.DebugFlags.UI.HwLayers, "[TaskView|enableHwLayers]");
         mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
     }
 
     /** Disable the hw layers on this task view */
     void disableHwLayers() {
-        Console.log(Constants.DebugFlags.UI.HwLayers, "[TaskView|disableHwLayers]");
         mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null);
     }
 
+    /**** TaskCallbacks Implementation ****/
+
     @Override
     public void onTaskDataChanged(Task task) {
         Console.log(Constants.DebugFlags.App.EnableBackgroundTaskLoading,
@@ -380,6 +380,16 @@
     }
 
     @Override
+    public void onTaskBound() {
+        syncToTask();
+    }
+
+    @Override
+    public void onTaskUnbound() {
+        unbindFromTask();
+    }
+
+    @Override
     public void onClick(View v) {
         mCb.onTaskIconClicked(this);
     }
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index b9b87b1..e45b98c 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -340,6 +340,13 @@
                 getWindowManager());
         // Get the crop
         RectF cropRect = mCropView.getCrop();
+
+        // Due to rounding errors in the cropview renderer the edges can be slightly offset
+        // therefore we ensure that the boundaries are sanely defined
+        cropRect.left = Math.max(0, cropRect.left);
+        cropRect.right = Math.min(mCropView.getWidth(), cropRect.right);
+        cropRect.top = Math.max(0, cropRect.top);
+        cropRect.bottom = Math.min(mCropView.getHeight(), cropRect.bottom);
         int cropRotation = mCropView.getImageRotation();
         float cropScale = mCropView.getWidth() / (float) cropRect.width();
 
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 3dcb488..e6163bd 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -457,6 +457,9 @@
      * @param userId the new active user's UserId
      */
     private void switchUser(int userId) {
+        if (mCurrentUserId == userId) {
+            return;
+        }
         mBlacklist.switchUser(userId);
         mLocationHandler.removeMessages(MSG_LOCATION_CHANGED);
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index c9f9a25..1ed943c 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -142,25 +142,40 @@
         class DefaultState extends State {
             @Override
             public boolean processMessage(Message msg) {
+                ClientInfo cInfo = null;
                 switch (msg.what) {
                     case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                         if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                             AsyncChannel c = (AsyncChannel) msg.obj;
                             if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
                             c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
-                            ClientInfo cInfo = new ClientInfo(c, msg.replyTo);
+                            cInfo = new ClientInfo(c, msg.replyTo);
                             mClients.put(msg.replyTo, cInfo);
                         } else {
                             Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
                         }
                         break;
                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                        if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
-                            Slog.e(TAG, "Send failed, client connection lost");
-                        } else {
-                            if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
+                        switch (msg.arg1) {
+                            case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
+                                Slog.e(TAG, "Send failed, client connection lost");
+                                break;
+                            case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
+                                if (DBG) Slog.d(TAG, "Client disconnected");
+                                break;
+                            default:
+                                if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
+                                break;
                         }
-                        mClients.remove(msg.replyTo);
+                        cInfo = mClients.get(msg.replyTo);
+                        if (cInfo != null) {
+                            cInfo.expungeAllRequests();
+                            mClients.remove(msg.replyTo);
+                        }
+                        //Last client
+                        if (mClients.size() == 0) {
+                            stopMDnsDaemon();
+                        }
                         break;
                     case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
                         AsyncChannel ac = new AsyncChannel();
@@ -238,13 +253,15 @@
                 return false;
             }
 
-            private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
+            private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
                 clientInfo.mClientIds.put(clientId, globalId);
+                clientInfo.mClientRequests.put(clientId, what);
                 mIdToClientInfoMap.put(globalId, clientInfo);
             }
 
             private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
                 clientInfo.mClientIds.remove(clientId);
+                clientInfo.mClientRequests.remove(clientId);
                 mIdToClientInfoMap.remove(globalId);
             }
 
@@ -264,10 +281,6 @@
                         result = NOT_HANDLED;
                         break;
                     case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                        //Last client
-                        if (mClients.size() == 1) {
-                            stopMDnsDaemon();
-                        }
                         result = NOT_HANDLED;
                         break;
                     case NsdManager.DISABLE:
@@ -291,7 +304,7 @@
                                 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
                                         servInfo.getServiceType());
                             }
-                            storeRequestMap(msg.arg2, id, clientInfo);
+                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
                             replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
                         } else {
                             stopServiceDiscovery(id);
@@ -330,7 +343,7 @@
                         id = getUniqueId();
                         if (registerService(id, (NsdServiceInfo) msg.obj)) {
                             if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
-                            storeRequestMap(msg.arg2, id, clientInfo);
+                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
                             // Return success after mDns reports success
                         } else {
                             unregisterService(id);
@@ -371,7 +384,7 @@
                         id = getUniqueId();
                         if (resolveService(id, servInfo)) {
                             clientInfo.mResolvedService = new NsdServiceInfo();
-                            storeRequestMap(msg.arg2, id, clientInfo);
+                            storeRequestMap(msg.arg2, id, clientInfo, msg.what);
                         } else {
                             replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
                                     NsdManager.FAILURE_INTERNAL_ERROR);
@@ -477,7 +490,7 @@
 
                         int id2 = getUniqueId();
                         if (getAddrInfo(id2, cooked[3])) {
-                            storeRequestMap(clientId, id2, clientInfo);
+                            storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
                         } else {
                             clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
                                     NsdManager.FAILURE_INTERNAL_ERROR, clientId);
@@ -821,6 +834,9 @@
         /* A map from client id to unique id sent to mDns */
         private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
 
+        /* A map from client id to the type of the request we had received */
+        private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
+
         private ClientInfo(AsyncChannel c, Messenger m) {
             mChannel = c;
             mMessenger = m;
@@ -834,10 +850,41 @@
             sb.append("mMessenger ").append(mMessenger).append("\n");
             sb.append("mResolvedService ").append(mResolvedService).append("\n");
             for(int i = 0; i< mClientIds.size(); i++) {
-                sb.append("clientId ").append(mClientIds.keyAt(i));
-                sb.append(" mDnsId ").append(mClientIds.valueAt(i)).append("\n");
+                int clientID = mClientIds.keyAt(i);
+                sb.append("clientId ").append(clientID).
+                    append(" mDnsId ").append(mClientIds.valueAt(i)).
+                    append(" type ").append(mClientRequests.get(clientID)).append("\n");
             }
             return sb.toString();
         }
+
+        // Remove any pending requests from the global map when we get rid of a client,
+        // and send cancellations to the daemon.
+        private void expungeAllRequests() {
+            int globalId, clientId, i;
+            for (i = 0; i < mClientIds.size(); i++) {
+                clientId = mClientIds.keyAt(i);
+                globalId = mClientIds.valueAt(i);
+                mIdToClientInfoMap.remove(globalId);
+                if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
+                        " global-ID " + globalId + " type " + mClientRequests.get(clientId));
+                switch (mClientRequests.get(clientId)) {
+                    case NsdManager.DISCOVER_SERVICES:
+                        stopServiceDiscovery(globalId);
+                        break;
+                    case NsdManager.RESOLVE_SERVICE:
+                        stopResolveService(globalId);
+                        break;
+                    case NsdManager.REGISTER_SERVICE:
+                        unregisterService(globalId);
+                        break;
+                    default:
+                        break;
+                }
+            }
+            mClientIds.clear();
+            mClientRequests.clear();
+        }
+
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 9315648..3c7ef61 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1202,6 +1202,19 @@
                 resultRecord.removeResultsLocked(
                     sourceRecord, resultWho, requestCode);
             }
+            if (sourceRecord.launchedFromUid == callingUid) {
+                // The new activity is being launched from the same uid as the previous
+                // activity in the flow, and asking to forward its result back to the
+                // previous.  In this case the activity is serving as a trampoline between
+                // the two, so we also want to update its launchedFromPackage to be the
+                // same as the previous activity.  Note that this is safe, since we know
+                // these two packages come from the same uid; the caller could just as
+                // well have supplied that same package name itself.  This specifially
+                // deals with the case of an intent picker/chooser being launched in the app
+                // flow to redirect to an activity picked by the user, where we want the final
+                // activity to consider it to have been launched by the previous app activity.
+                callingPackage = sourceRecord.launchedFromPackage;
+            }
         }
 
         if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index ff5c935..118cba4 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -335,6 +335,27 @@
     }
 
     @Override
+    public Drawable getActivityBanner(ComponentName activityName)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityBanner(Intent intent) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationBanner(ApplicationInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationBanner(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public Drawable getApplicationIcon(ApplicationInfo info) {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 78ef06d..b16b4aa 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -237,7 +237,7 @@
         result.percent = '%';
         result.perMill = '\u2030';
         result.monetarySeparator = ' ';
-        result.minusSign = '-';
+        result.minusSign = "-";
         result.exponentSeparator = "e";
         result.infinity = "\u221E";
         result.NaN = "NaN";