Merge "Not showing hover menu for trivial selections."
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 5c6fe46..38562da 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -150,7 +150,13 @@
     }
 
     public void setEnterActivityOptions(Activity activity, ActivityOptions options) {
-        if (activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
+        final Window window = activity.getWindow();
+        if (window == null) {
+            return;
+        }
+        // ensure Decor View has been created so that the window features are activated
+        window.getDecorView();
+        if (window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
                 && options != null && mEnterActivityOptions == null
                 && mEnterTransitionCoordinator == null
                 && options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 84cbea9..9081ef8 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -1078,8 +1078,8 @@
      */
     private ArrayList<View> addTransitionTargets(final TransitionState state,
             final Transition enterTransition, final TransitionSet sharedElementTransition,
-            final Transition overallTransition, final View container,
-            final Fragment inFragment, final Fragment outFragment,
+            final Transition exitTransition, final Transition overallTransition,
+            final View container, final Fragment inFragment, final Fragment outFragment,
             final ArrayList<View> hiddenFragmentViews, final boolean isBack,
             final ArrayList<View> sharedElementTargets) {
         if (enterTransition == null && sharedElementTransition == null &&
@@ -1103,6 +1103,13 @@
                         if (sharedElementTransition != null) {
                             namedViews = mapSharedElementsIn(state, isBack, inFragment);
                             removeTargets(sharedElementTransition, sharedElementTargets);
+                            // keep the nonExistentView as excluded so the list doesn't get emptied
+                            sharedElementTargets.remove(state.nonExistentView);
+                            excludeViews(exitTransition, sharedElementTransition,
+                                    sharedElementTargets, false);
+                            excludeViews(enterTransition, sharedElementTransition,
+                                    sharedElementTargets, false);
+
                             setSharedElementTargets(sharedElementTransition,
                                     state.nonExistentView, namedViews, sharedElementTargets);
 
@@ -1126,6 +1133,12 @@
                             }
                             setSharedElementEpicenter(enterTransition, state);
                         }
+
+                        excludeViews(exitTransition, enterTransition, enteringViews, true);
+                        excludeViews(exitTransition, sharedElementTransition, sharedElementTargets,
+                                true);
+                        excludeViews(enterTransition, sharedElementTransition, sharedElementTargets,
+                                true);
                         return true;
                     }
                 });
@@ -1279,6 +1292,9 @@
             if (exitingViews == null || exitingViews.isEmpty()) {
                 exitTransition = null;
             }
+            excludeViews(enterTransition, exitTransition, exitingViews, true);
+            excludeViews(enterTransition, sharedElementTransition, sharedElementTargets, true);
+            excludeViews(exitTransition, sharedElementTransition, sharedElementTargets, true);
 
             // Set the epicenter of the exit transition
             if (mSharedElementTargetNames != null && namedViews != null) {
@@ -1299,7 +1315,7 @@
             if (transition != null) {
                 ArrayList<View> hiddenFragments = new ArrayList<View>();
                 ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
-                        sharedElementTransition, transition, sceneRoot, inFragment,
+                        sharedElementTransition, exitTransition, transition, sceneRoot, inFragment,
                         outFragment, hiddenFragments, isBack, sharedElementTargets);
 
                 transition.setNameOverrides(state.nameOverrides);
@@ -1379,6 +1395,16 @@
         return false;
     }
 
+    private static void excludeViews(Transition transition, Transition fromTransition,
+            ArrayList<View> views, boolean exclude) {
+        if (transition != null) {
+            final int viewCount = fromTransition == null ? 0 : views.size();
+            for (int i = 0; i < viewCount; i++) {
+                transition.excludeTarget(views.get(i), exclude);
+            }
+        }
+    }
+
     /**
      * After the transition has started, remove all targets that we added to the transitions
      * so that the transitions are left in a clean state.
@@ -1396,9 +1422,15 @@
                     sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
                     if (enterTransition != null) {
                         removeTargets(enterTransition, enteringViews);
+                        excludeViews(enterTransition, exitTransition, exitingViews, false);
+                        excludeViews(enterTransition, sharedElementTransition, sharedElementTargets,
+                                false);
                     }
                     if (exitTransition != null) {
                         removeTargets(exitTransition, exitingViews);
+                        excludeViews(exitTransition, enterTransition, enteringViews, false);
+                        excludeViews(exitTransition, sharedElementTransition, sharedElementTargets,
+                                false);
                     }
                     if (sharedElementTransition != null) {
                         removeTargets(sharedElementTransition, sharedElementTargets);
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index 18dc262..954dcfb 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -364,18 +364,32 @@
             for (int k = 0; k < val.length; k += incr) {
                 switch (cmd) {
                     case 'm': // moveto - Start a new sub-path (relative)
-                        path.rMoveTo(val[k + 0], val[k + 1]);
                         currentX += val[k + 0];
                         currentY += val[k + 1];
-                        currentSegmentStartX = currentX;
-                        currentSegmentStartY = currentY;
+                        if (k > 0) {
+                            // According to the spec, if a moveto is followed by multiple
+                            // pairs of coordinates, the subsequent pairs are treated as
+                            // implicit lineto commands.
+                            path.rLineTo(val[k + 0], val[k + 1]);
+                        } else {
+                            path.rMoveTo(val[k + 0], val[k + 1]);
+                            currentSegmentStartX = currentX;
+                            currentSegmentStartY = currentY;
+                        }
                         break;
                     case 'M': // moveto - Start a new sub-path
-                        path.moveTo(val[k + 0], val[k + 1]);
                         currentX = val[k + 0];
                         currentY = val[k + 1];
-                        currentSegmentStartX = currentX;
-                        currentSegmentStartY = currentY;
+                        if (k > 0) {
+                            // According to the spec, if a moveto is followed by multiple
+                            // pairs of coordinates, the subsequent pairs are treated as
+                            // implicit lineto commands.
+                            path.lineTo(val[k + 0], val[k + 1]);
+                        } else {
+                            path.moveTo(val[k + 0], val[k + 1]);
+                            currentSegmentStartX = currentX;
+                            currentSegmentStartY = currentY;
+                        }
                         break;
                     case 'l': // lineto - Draw a line from the current point (relative)
                         path.rLineTo(val[k + 0], val[k + 1]);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d26e914..84ba450 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -576,21 +576,20 @@
                             // right away, anyway.
                             return;
                         case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
-                            throw new WindowManager.BadTokenException(
-                                    "Unable to add window " + mWindow +
-                                    " -- another window of this type already exists");
+                            throw new WindowManager.BadTokenException("Unable to add window "
+                                    + mWindow + " -- another window of type "
+                                    + mWindowAttributes.type + " already exists");
                         case WindowManagerGlobal.ADD_PERMISSION_DENIED:
-                            throw new WindowManager.BadTokenException(
-                                    "Unable to add window " + mWindow +
-                                    " -- permission denied for this window type");
+                            throw new WindowManager.BadTokenException("Unable to add window "
+                                    + mWindow + " -- permission denied for window type "
+                                    + mWindowAttributes.type);
                         case WindowManagerGlobal.ADD_INVALID_DISPLAY:
-                            throw new WindowManager.InvalidDisplayException(
-                                    "Unable to add window " + mWindow +
-                                    " -- the specified display can not be found");
+                            throw new WindowManager.InvalidDisplayException("Unable to add window "
+                                    + mWindow + " -- the specified display can not be found");
                         case WindowManagerGlobal.ADD_INVALID_TYPE:
-                            throw new WindowManager.InvalidDisplayException(
-                                    "Unable to add window " + mWindow
-                                    + " -- the specified window type is not valid");
+                            throw new WindowManager.InvalidDisplayException("Unable to add window "
+                                    + mWindow + " -- the specified window type "
+                                    + mWindowAttributes.type + " is not valid");
                     }
                     throw new RuntimeException(
                             "Unable to add window -- unknown error code " + res);
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 16f6f4b..a6c72a3 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -16,9 +16,6 @@
 
 #include <GLES2/gl2.h>
 
-#include <SkCanvas.h>
-#include <SkPixelRef.h>
-
 #include <utils/Mutex.h>
 
 #include "AssetAtlas.h"
@@ -169,7 +166,7 @@
         if (canCache) {
             texture = new Texture(Caches::getInstance());
             texture->bitmapSize = size;
-            generateTexture(bitmap, texture, false);
+            Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
 
             mSize += size;
             TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
@@ -182,7 +179,7 @@
     } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
         // Texture was in the cache but is dirty, re-upload
         // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
-        generateTexture(bitmap, texture, true);
+        Caches::getInstance().textureState().generateTexture(bitmap, texture, true);
     }
 
     return texture;
@@ -207,7 +204,7 @@
         const uint32_t size = bitmap->rowBytes() * bitmap->height();
         texture = new Texture(Caches::getInstance());
         texture->bitmapSize = size;
-        generateTexture(bitmap, texture, false);
+        Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
         texture->cleanup = true;
     }
 
@@ -249,133 +246,5 @@
     }
 }
 
-void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) {
-    SkAutoLockPixels alp(*bitmap);
-
-    if (!bitmap->readyToDraw()) {
-        ALOGE("Cannot generate texture from bitmap");
-        return;
-    }
-
-    ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
-
-    // We could also enable mipmapping if both bitmap dimensions are powers
-    // of 2 but we'd have to deal with size changes. Let's keep this simple
-    const bool canMipMap = Caches::getInstance().extensions().hasNPot();
-
-    // If the texture had mipmap enabled but not anymore,
-    // force a glTexImage2D to discard the mipmap levels
-    const bool resize = !regenerate || bitmap->width() != int(texture->width) ||
-            bitmap->height() != int(texture->height) ||
-            (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
-
-    if (!regenerate) {
-        glGenTextures(1, &texture->id);
-    }
-
-    texture->generation = bitmap->getGenerationID();
-    texture->width = bitmap->width();
-    texture->height = bitmap->height();
-
-    Caches::getInstance().textureState().bindTexture(texture->id);
-
-    switch (bitmap->colorType()) {
-    case kAlpha_8_SkColorType:
-        uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
-                texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
-        texture->blend = true;
-        break;
-    case kRGB_565_SkColorType:
-        uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
-                texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
-        texture->blend = false;
-        break;
-    case kN32_SkColorType:
-        uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
-                texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
-        // Do this after calling getPixels() to make sure Skia's deferred
-        // decoding happened
-        texture->blend = !bitmap->isOpaque();
-        break;
-    case kARGB_4444_SkColorType:
-    case kIndex_8_SkColorType:
-        uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
-        texture->blend = !bitmap->isOpaque();
-        break;
-    default:
-        ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType());
-        break;
-    }
-
-    if (canMipMap) {
-        texture->mipMap = bitmap->hasHardwareMipMap();
-        if (texture->mipMap) {
-            glGenerateMipmap(GL_TEXTURE_2D);
-        }
-    }
-
-    if (!regenerate) {
-        texture->setFilter(GL_NEAREST);
-        texture->setWrap(GL_CLAMP_TO_EDGE);
-    }
-}
-
-void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap,
-        uint32_t width, uint32_t height) {
-    SkBitmap rgbaBitmap;
-    rgbaBitmap.allocPixels(SkImageInfo::MakeN32(width, height, bitmap->alphaType()));
-    rgbaBitmap.eraseColor(0);
-
-    SkCanvas canvas(rgbaBitmap);
-    canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
-
-    uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(),
-            width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
-}
-
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
-        GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
-    glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
-    const bool useStride = stride != width
-            && Caches::getInstance().extensions().hasUnpackRowLength();
-    if ((stride == width) || useStride) {
-        if (useStride) {
-            glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
-        }
-
-        if (resize) {
-            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
-        } else {
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
-        }
-
-        if (useStride) {
-            glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-        }
-    } else {
-        //  With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
-        //  if the stride doesn't match the width
-
-        GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
-        if (!temp) return;
-
-        uint8_t * pDst = (uint8_t *)temp;
-        uint8_t * pSrc = (uint8_t *)data;
-        for (GLsizei i = 0; i < height; i++) {
-            memcpy(pDst, pSrc, width * bpp);
-            pDst += width * bpp;
-            pSrc += stride * bpp;
-        }
-
-        if (resize) {
-            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
-        } else {
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
-        }
-
-        free(temp);
-    }
-}
-
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index ebd1885..191c8a8 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -144,18 +144,6 @@
     Texture* get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType);
     Texture* getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType);
 
-    /**
-     * Generates the texture from a bitmap into the specified texture structure.
-     *
-     * @param regenerate If true, the bitmap data is reuploaded into the texture, but
-     *        no new texture is generated.
-     */
-    void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate = false);
-
-    void uploadLoFiTexture(bool resize, const SkBitmap* bitmap, uint32_t width, uint32_t height);
-    void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
-            GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
-
     LruCache<uint32_t, Texture*> mCache;
 
     uint32_t mSize;
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index 987d4cd..1f50f71 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -15,6 +15,14 @@
  */
 #include "renderstate/TextureState.h"
 
+#include "Caches.h"
+#include "utils/TraceUtils.h"
+
+#include <GLES3/gl3.h>
+#include <memory>
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -26,6 +34,134 @@
     GL_TEXTURE3
 };
 
+static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp,
+        GLsizei width, GLsizei height, const GLvoid * data) {
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
+    const bool useStride = stride != width
+            && Caches::getInstance().extensions().hasUnpackRowLength();
+    if ((stride == width) || useStride) {
+        if (useStride) {
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+        }
+
+        if (resize) {
+            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+        } else {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
+        }
+
+        if (useStride) {
+            glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+        }
+    } else {
+        //  With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+        //  if the stride doesn't match the width
+
+        GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+        if (!temp) return;
+
+        uint8_t * pDst = (uint8_t *)temp;
+        uint8_t * pSrc = (uint8_t *)data;
+        for (GLsizei i = 0; i < height; i++) {
+            memcpy(pDst, pSrc, width * bpp);
+            pDst += width * bpp;
+            pSrc += stride * bpp;
+        }
+
+        if (resize) {
+            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
+        } else {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
+        }
+
+        free(temp);
+    }
+}
+
+static void uploadSkBitmapToTexture(const SkBitmap& bitmap,
+        bool resize, GLenum format, GLenum type) {
+    uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(),
+            bitmap.width(), bitmap.height(), bitmap.getPixels());
+}
+
+void TextureState::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) {
+    SkAutoLockPixels alp(*bitmap);
+
+    if (!bitmap->readyToDraw()) {
+        ALOGE("Cannot generate texture from bitmap");
+        return;
+    }
+
+    ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height());
+
+    // We could also enable mipmapping if both bitmap dimensions are powers
+    // of 2 but we'd have to deal with size changes. Let's keep this simple
+    const bool canMipMap = Caches::getInstance().extensions().hasNPot();
+
+    // If the texture had mipmap enabled but not anymore,
+    // force a glTexImage2D to discard the mipmap levels
+    const bool resize = !regenerate || bitmap->width() != int(texture->width) ||
+            bitmap->height() != int(texture->height) ||
+            (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
+
+    if (!regenerate) {
+        glGenTextures(1, &texture->id);
+    }
+
+    texture->generation = bitmap->getGenerationID();
+    texture->width = bitmap->width();
+    texture->height = bitmap->height();
+
+    bindTexture(texture->id);
+
+    switch (bitmap->colorType()) {
+    case kAlpha_8_SkColorType:
+        uploadSkBitmapToTexture(*bitmap, resize, GL_ALPHA, GL_UNSIGNED_BYTE);
+        texture->blend = true;
+        break;
+    case kRGB_565_SkColorType:
+        uploadSkBitmapToTexture(*bitmap, resize, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
+        texture->blend = false;
+        break;
+    case kN32_SkColorType:
+        uploadSkBitmapToTexture(*bitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
+        // Do this after calling getPixels() to make sure Skia's deferred
+        // decoding happened
+        texture->blend = !bitmap->isOpaque();
+        break;
+    case kARGB_4444_SkColorType:
+    case kIndex_8_SkColorType: {
+        SkBitmap rgbaBitmap;
+        rgbaBitmap.allocPixels(SkImageInfo::MakeN32(texture->width, texture->height,
+                bitmap->alphaType()));
+        rgbaBitmap.eraseColor(0);
+
+        SkCanvas canvas(rgbaBitmap);
+        canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
+
+        uploadSkBitmapToTexture(rgbaBitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE);
+        texture->blend = !bitmap->isOpaque();
+        break;
+    }
+    default:
+        ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType());
+        break;
+    }
+
+    if (canMipMap) {
+        texture->mipMap = bitmap->hasHardwareMipMap();
+        if (texture->mipMap) {
+            glGenerateMipmap(GL_TEXTURE_2D);
+        }
+    }
+
+    if (!regenerate) {
+        texture->setFilter(GL_NEAREST);
+        texture->setWrap(GL_CLAMP_TO_EDGE);
+    }
+}
+
 TextureState::TextureState()
         : mTextureUnit(0) {
     glActiveTexture(kTextureUnits[0]);
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index d3c014c..3a2b85a 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -23,9 +23,13 @@
 #include <SkXfermode.h>
 #include <memory>
 
+class SkBitmap;
+
 namespace android {
 namespace uirenderer {
 
+class Texture;
+
 class TextureState {
     friend class Caches; // TODO: move to RenderState
 public:
@@ -71,6 +75,14 @@
      * Clear the cache of bound textures.
      */
     void unbindTexture(GLuint texture);
+
+    /**
+     * Generates the texture from a bitmap into the specified texture structure.
+     *
+     * @param regenerate If true, the bitmap data is reuploaded into the texture, but
+     *        no new texture is generated.
+     */
+    void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate);
 private:
     // total number of texture units available for use
     static const int kTextureUnitsCount = 4;
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index f52d755..66233b8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -25,6 +25,7 @@
 import android.os.SystemProperties;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 
 public class TetherUtil {
 
@@ -62,6 +63,13 @@
         return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
     }
 
+    private static boolean isEntitlementCheckRequired(Context context) {
+        final CarrierConfigManager configManager = (CarrierConfigManager) context
+             .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        return configManager.getConfig().getBoolean(CarrierConfigManager
+             .KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+    }
+
     public static boolean isProvisioningNeeded(Context context) {
         // Keep in sync with other usage of config_mobile_hotspot_provision_app.
         // ConnectivityManager#enforceTetherChangePermission
@@ -71,6 +79,10 @@
                 || provisionApp == null) {
             return false;
         }
+        // Check carrier config for entitlement checks
+        if (isEntitlementCheckRequired(context) == false) {
+            return false;
+        }
         return (provisionApp.length == 2);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d3af8f03..33ebfff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -315,6 +315,9 @@
     boolean mLeaveOpenOnKeyguardHide;
     KeyguardIndicationController mKeyguardIndicationController;
 
+    // Keyguard is going away soon.
+    private boolean mKeyguardGoingAway;
+    // Keyguard is actually fading away now.
     private boolean mKeyguardFadingAway;
     private long mKeyguardFadingAwayDelay;
     private long mKeyguardFadingAwayDuration;
@@ -3596,6 +3599,7 @@
 
         // Treat Keyguard exit animation as an app transition to achieve nice transition for status
         // bar.
+        mKeyguardGoingAway = true;
         mIconController.appTransitionPending();
     }
 
@@ -3627,6 +3631,7 @@
      */
     public void finishKeyguardFadingAway() {
         mKeyguardFadingAway = false;
+        mKeyguardGoingAway = false;
     }
 
     public void stopWaitingForKeyguardExit() {
@@ -4137,9 +4142,8 @@
     public void appTransitionStarting(long startTime, long duration) {
 
         // Use own timings when Keyguard is going away, see keyguardGoingAway and
-        // setKeyguardFadingAway. When duration is 0, skip this one because no animation is really
-        // playing.
-        if (!mKeyguardFadingAway && duration > 0) {
+        // setKeyguardFadingAway.
+        if (!mKeyguardGoingAway) {
             mIconController.appTransitionStarting(startTime, duration);
         }
         if (mIconPolicy != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index aafaf83..93dc6cb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1327,4 +1327,4 @@
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
         Slog.i(TAG, name);
     }
-}
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0e858de..b868832 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -78,6 +78,15 @@
     public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
 
     /**
+     * Flag to require or skip entitlement checks.
+     * If true, entitlement checks will be executed if device has been configured for it,
+     * If false, entitlement checks will be skipped.
+     * @hide
+     */
+    public static final String
+            KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+
+    /**
      * If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
      * The pattern is set on a per-platform basis using config_virtualKeyVibePattern. To be
      * consistent with the regular Dialer, this value should agree with the corresponding values
@@ -511,6 +520,7 @@
         sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
         sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
         sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
+        sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
         sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
         sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, "");
         sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index 24df85b..0e678cd 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -11,17 +11,20 @@
 LOCAL_RESOURCE_DIR := \
     $(LOCAL_PATH)/res \
     frameworks/support/v7/appcompat/res \
-    frameworks/support/v7/cardview/res
+    frameworks/support/v7/cardview/res \
+    frameworks/support/v7/recyclerview/res
 
 LOCAL_AAPT_FLAGS := \
     --auto-add-overlay \
     --extra-packages android.support.v7.appcompat \
-    --extra-packages android.support.v7.cardview
+    --extra-packages android.support.v7.cardview \
+    --extra-packages android.support.v7.recyclerview
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-v4 \
     android-support-v7-appcompat \
-    android-support-v7-cardview
+    android-support-v7-cardview \
+    android-support-v7-recyclerview
 
 LOCAL_PACKAGE_NAME := UiBench
 
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 9b3d186..7b4f01c 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -83,6 +83,30 @@
                 <category android:name="com.android.test.uibench.TEST" />
             </intent-filter>
         </activity>
+        <activity
+            android:name=".TrivialRecyclerViewActivity"
+            android:label="General/Trivial Recycler ListView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ActivityTransition"
+            android:label="Transitions/Activity Transition" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ActivityTransitionDetails"
+            android:label="Transitions/Activity Transition " >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <!-- Part of ActivityTransition test above, so not in TEST category -->
+            </intent-filter>
+        </activity>
 
         <!-- Rendering -->
         <activity
diff --git a/tests/UiBench/build.gradle b/tests/UiBench/build.gradle
index deecbb6..0756a8a 100644
--- a/tests/UiBench/build.gradle
+++ b/tests/UiBench/build.gradle
@@ -32,7 +32,8 @@
 
 dependencies {
     // Dependencies enumerated specifically for platform-independent / reproducible builds.
-    compile 'com.android.support:support-v4:23.0.0'
-    compile 'com.android.support:appcompat-v7:23.0.0'
-    compile 'com.android.support:cardview-v7:23.0.0'
+    compile 'com.android.support:support-v4:23.0.1'
+    compile 'com.android.support:appcompat-v7:23.0.1'
+    compile 'com.android.support:cardview-v7:23.0.1'
+    compile 'com.android.support:recyclerview-v7:23.0.1'
 }
diff --git a/tests/UiBench/res/drawable-nodpi/ball.jpg b/tests/UiBench/res/drawable-nodpi/ball.jpg
new file mode 100644
index 0000000..2960b73
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/ball.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/block.jpg b/tests/UiBench/res/drawable-nodpi/block.jpg
new file mode 100644
index 0000000..04c22a0
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/block.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/ducky.jpg b/tests/UiBench/res/drawable-nodpi/ducky.jpg
new file mode 100644
index 0000000..830bbe3
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/ducky.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/frantic.jpg b/tests/UiBench/res/drawable-nodpi/frantic.jpg
new file mode 100644
index 0000000..4c62333
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/frantic.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/jellies.jpg b/tests/UiBench/res/drawable-nodpi/jellies.jpg
new file mode 100644
index 0000000..ee2b5c6
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/jellies.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/mug.jpg b/tests/UiBench/res/drawable-nodpi/mug.jpg
new file mode 100644
index 0000000..e149e19
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/mug.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/pencil.jpg b/tests/UiBench/res/drawable-nodpi/pencil.jpg
new file mode 100644
index 0000000..e348311
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/pencil.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/scissors.jpg b/tests/UiBench/res/drawable-nodpi/scissors.jpg
new file mode 100644
index 0000000..caf0ce8
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/scissors.jpg
Binary files differ
diff --git a/tests/UiBench/res/drawable-nodpi/woot.jpg b/tests/UiBench/res/drawable-nodpi/woot.jpg
new file mode 100644
index 0000000..ccaef67
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/woot.jpg
Binary files differ
diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml
new file mode 100644
index 0000000..d4c6610
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_transition.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="true"
+    android:columnCount="2"
+    android:rowCount="4">
+    <ImageView
+        android:id="@+id/ducky"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:layout_column="0"
+        android:layout_row="0"
+        android:src="@drawable/ducky"
+        android:onClick="clicked"
+        android:transitionName="ducky"/>
+    <ImageView
+        android:id="@+id/woot"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:src="@drawable/woot"
+        android:layout_column="1"
+        android:layout_row="0"
+        android:onClick="clicked"
+        android:transitionName="woot"/>
+    <ImageView
+        android:id="@+id/ball"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:src="@drawable/ball"
+        android:layout_column="0"
+        android:layout_row="1"
+        android:onClick="clicked"
+        android:transitionName="ball"/>
+    <ImageView
+        android:id="@+id/block"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:src="@drawable/block"
+        android:layout_column="1"
+        android:layout_row="1"
+        android:onClick="clicked"
+        android:transitionName="block"/>
+    <ImageView
+        android:id="@+id/jellies"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:src="@drawable/jellies"
+        android:layout_column="0"
+        android:layout_row="2"
+        android:onClick="clicked"
+        android:transitionName="jellies"/>
+    <ImageView
+        android:id="@+id/mug"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:src="@drawable/mug"
+        android:layout_column="1"
+        android:layout_row="2"
+        android:onClick="clicked"
+        android:transitionName="mug"/>
+    <ImageView
+        android:id="@+id/pencil"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:src="@drawable/pencil"
+        android:layout_column="0"
+        android:layout_row="3"
+        android:onClick="clicked"
+        android:transitionName="pencil"/>
+    <ImageView
+        android:id="@+id/scissors"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:scaleType="centerCrop"
+        android:src="@drawable/scissors"
+        android:layout_column="1"
+        android:layout_row="3"
+        android:onClick="clicked"
+        android:transitionName="scissors"/>
+</GridLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_transition_details.xml b/tests/UiBench/res/layout/activity_transition_details.xml
new file mode 100644
index 0000000..1022d2f
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_transition_details.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <ImageView
+        android:id="@+id/titleImage"
+        android:layout_height="0px"
+        android:layout_weight="1"
+        android:layout_width="match_parent"
+        android:scaleType="centerCrop"
+        android:transitionName="hero"
+        android:onClick="clicked"/>
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="2dp"
+            android:background="#808080"/>
+        <TextView
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:text="Sample Picture"
+            android:textSize="30sp"
+            android:textColor="#FFF"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/recycler_view.xml b/tests/UiBench/res/layout/recycler_view.xml
new file mode 100644
index 0000000..54c5b58
--- /dev/null
+++ b/tests/UiBench/res/layout/recycler_view.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<android.support.v7.widget.RecyclerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/recyclerView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
new file mode 100644
index 0000000..1106a13
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.app.ActivityOptions;
+import android.app.SharedElementCallback;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.List;
+import java.util.Map;
+
+public class ActivityTransition extends AppCompatActivity {
+    private static final String KEY_ID = "ViewTransitionValues:id";
+
+    private ImageView mHero;
+
+    public static final int[] DRAWABLES = {
+            R.drawable.ball,
+            R.drawable.block,
+            R.drawable.ducky,
+            R.drawable.jellies,
+            R.drawable.mug,
+            R.drawable.pencil,
+            R.drawable.scissors,
+            R.drawable.woot,
+    };
+
+    public static final int[] IDS = {
+            R.id.ball,
+            R.id.block,
+            R.id.ducky,
+            R.id.jellies,
+            R.id.mug,
+            R.id.pencil,
+            R.id.scissors,
+            R.id.woot,
+    };
+
+    public static final String[] NAMES = {
+            "ball",
+            "block",
+            "ducky",
+            "jellies",
+            "mug",
+            "pencil",
+            "scissors",
+            "woot",
+    };
+
+    public static int getIdForKey(String id) {
+        return IDS[getIndexForKey(id)];
+    }
+
+    public static int getDrawableIdForKey(String id) {
+        return DRAWABLES[getIndexForKey(id)];
+    }
+
+    public static int getIndexForKey(String id) {
+        for (int i = 0; i < NAMES.length; i++) {
+            String name = NAMES[i];
+            if (name.equals(id)) {
+                return i;
+            }
+        }
+        return 2;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
+        setContentView(R.layout.activity_transition);
+        setupHero();
+    }
+
+    private void setupHero() {
+        String name = getIntent().getStringExtra(KEY_ID);
+        mHero = null;
+        if (name != null) {
+            mHero = (ImageView) findViewById(getIdForKey(name));
+            setEnterSharedElementCallback(new SharedElementCallback() {
+                @Override
+                public void onMapSharedElements(List<String> names,
+                        Map<String, View> sharedElements) {
+                    sharedElements.put("hero", mHero);
+                }
+            });
+        }
+    }
+
+    public void clicked(View v) {
+        mHero = (ImageView) v;
+        Intent intent = new Intent(this, ActivityTransitionDetails.class);
+        intent.putExtra(KEY_ID, v.getTransitionName());
+        ActivityOptions activityOptions
+                = ActivityOptions.makeSceneTransitionAnimation(this, mHero, "hero");
+        startActivity(intent, activityOptions.toBundle());
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java
new file mode 100644
index 0000000..a654c61
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.test.uibench.ActivityTransition;
+import com.android.test.uibench.R;
+
+
+public class ActivityTransitionDetails extends AppCompatActivity {
+    private static final String KEY_ID = "ViewTransitionValues:id";
+    private int mImageResourceId = R.drawable.ducky;
+    private String mName = "ducky";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new ColorDrawable(Color.DKGRAY));
+        setContentView(R.layout.activity_transition_details);
+        ImageView titleImage = (ImageView) findViewById(R.id.titleImage);
+        titleImage.setImageDrawable(getHeroDrawable());
+    }
+
+    private Drawable getHeroDrawable() {
+        String name = getIntent().getStringExtra(KEY_ID);
+        if (name != null) {
+            mName = name;
+            mImageResourceId = ActivityTransition.getDrawableIdForKey(name);
+        }
+
+        return getResources().getDrawable(mImageResourceId);
+    }
+
+    public void clicked(View v) {
+        Intent intent = new Intent(this, ActivityTransition.class);
+        intent.putExtra(KEY_ID, mName);
+        ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
+                this, v, "hero");
+        startActivity(intent, activityOptions.toBundle());
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
index 84383ec..603244e 100644
--- a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
@@ -20,6 +20,8 @@
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 
+import com.android.test.uibench.listview.CompatListActivity;
+
 public class InflatingListActivity extends CompatListActivity {
     @Override
     protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
index 91d74ac..fc5be35 100644
--- a/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
@@ -18,6 +18,8 @@
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 
+import com.android.test.uibench.listview.CompatListActivity;
+
 public class TextCacheHighHitrateActivity extends CompatListActivity {
     @Override
     protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
index b526cde..14dc437 100644
--- a/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
@@ -18,6 +18,8 @@
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 
+import com.android.test.uibench.listview.CompatListActivity;
+
 public class TextCacheLowHitrateActivity extends CompatListActivity {
     @Override
     protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
index 339ac80..2625a99 100644
--- a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
@@ -18,6 +18,8 @@
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 
+import com.android.test.uibench.listview.CompatListActivity;
+
 public class TrivialListActivity extends CompatListActivity {
     @Override
     protected ListAdapter createListAdapter() {
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.java
new file mode 100644
index 0000000..4647ba7
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.support.v7.widget.RecyclerView;
+
+import com.android.test.uibench.recyclerview.RvArrayAdapter;
+import com.android.test.uibench.recyclerview.RvCompatListActivity;
+
+public class TrivialRecyclerViewActivity extends RvCompatListActivity {
+    @Override
+    protected RecyclerView.Adapter createAdapter() {
+        return new RvArrayAdapter(TextUtils.buildSimpleStringList());
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
similarity index 96%
rename from tests/UiBench/src/com/android/test/uibench/CompatListActivity.java
rename to tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
index 40ec453..214c074 100644
--- a/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.test.uibench;
+package com.android.test.uibench.listview;
 
 import android.os.Bundle;
 import android.support.v4.app.FragmentManager;
diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java
new file mode 100644
index 0000000..e5a3a49
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench.recyclerview;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class RvArrayAdapter extends RecyclerView.Adapter<RvArrayAdapter.ViewHolder> {
+    private String[] mDataSet;
+    private LayoutInflater mLayoutInflater;
+
+    public static class ViewHolder extends RecyclerView.ViewHolder {
+        private final TextView mTextView;
+
+        public ViewHolder(View v) {
+            super(v);
+            mTextView = (TextView) v.findViewById(android.R.id.text1);
+        }
+
+        public TextView getTextView() {
+            return mTextView;
+        }
+    }
+
+    public RvArrayAdapter(String[] dataSet) {
+        mDataSet = dataSet;
+    }
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
+        if (mLayoutInflater == null) {
+            mLayoutInflater = LayoutInflater.from(viewGroup.getContext());
+        }
+        View v = mLayoutInflater.inflate(android.R.layout.simple_list_item_1, viewGroup, false);
+
+        return new ViewHolder(v);
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
+        viewHolder.getTextView().setText(mDataSet[position]);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mDataSet.length;
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
new file mode 100644
index 0000000..e08dbc6
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench.recyclerview;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+import com.android.test.uibench.R;
+
+public abstract class RvCompatListActivity extends AppCompatActivity {
+    public static class RecyclerViewFragment extends Fragment {
+        RecyclerView.LayoutManager layoutManager;
+        RecyclerView.Adapter adapter;
+
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            RecyclerView recyclerView = (RecyclerView) inflater.inflate(
+                    R.layout.recycler_view, container, false);
+            recyclerView.setLayoutManager(layoutManager);
+            recyclerView.setAdapter(adapter);
+            return recyclerView;
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            RecyclerViewFragment fragment = new RecyclerViewFragment();
+            fragment.layoutManager = createLayoutManager(this);
+            fragment.adapter = createAdapter();
+            fm.beginTransaction().add(android.R.id.content, fragment).commit();
+        }
+    }
+
+    protected RecyclerView.LayoutManager createLayoutManager(Context context) {
+        return new LinearLayoutManager(context);
+    }
+
+    protected abstract RecyclerView.Adapter createAdapter();
+}