Merge "Add SlowNestedRecyclerViewActivity"
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index b7b4894..29154aa 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -102,10 +102,18 @@
         <activity
             android:name=".SlowBindRecyclerViewActivity"
             android:label="General/Slow Bind RecyclerView" >
-        <intent-filter>
-            <action android:name="android.intent.action.MAIN" />
-            <category android:name="com.android.test.uibench.TEST" />
-        </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".SlowNestedRecyclerViewActivity"
+            android:label="General/Slow Nested RecyclerView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
         </activity>
         <activity
             android:name=".ActivityTransition"
diff --git a/tests/UiBench/src/com/android/test/uibench/SlowNestedRecyclerViewActivity.java b/tests/UiBench/src/com/android/test/uibench/SlowNestedRecyclerViewActivity.java
new file mode 100644
index 0000000..305c051
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/SlowNestedRecyclerViewActivity.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2016 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.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.InsetDrawable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.test.uibench.recyclerview.RvCompatListActivity;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+public class SlowNestedRecyclerViewActivity extends RvCompatListActivity {
+    private static final int OUTER_ITEM_COUNT = 100;
+    private static final int INNER_ITEM_COUNT = 20;
+
+    private static final long INNER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(6);
+    private static final long INNER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1);
+    private static final long INNER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1);
+
+    private static final long OUTER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(3);
+    private static final long OUTER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1);
+    private static final long OUTER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1);
+
+    private SizeData mSizeData;
+
+    private static class SizeData {
+        final int innerItemWidth;
+        final int innerItemHeight;
+        final int headerHeight;
+
+        SizeData(Resources resources) {
+            innerItemWidth = (int) (resources.getDisplayMetrics().widthPixels / 3.3f);
+            innerItemHeight = (int) (innerItemWidth * 1.6f);
+            headerHeight = (int) (resources.getDisplayMetrics().heightPixels * 0.5f);
+        }
+    }
+
+    private SizeData getSizeData(Resources resources) {
+        if (mSizeData == null) {
+            mSizeData = new SizeData(resources);
+        }
+        return mSizeData;
+    }
+
+    @Override
+    protected RecyclerView.LayoutManager createLayoutManager(Context context) {
+        return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
+    }
+
+    @Override
+    protected RecyclerView.Adapter createAdapter() {
+        return new OuterAdapter();
+    }
+
+    private class InnerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            final long start = System.nanoTime();
+
+            final float density = parent.getResources().getDisplayMetrics().density;
+            View view = new View(parent.getContext()) {
+                @Override
+                protected void onAttachedToWindow() {
+                    final long start = System.nanoTime();
+                    super.onAttachedToWindow();
+                    while (System.nanoTime() - start < INNER_ITEM_ATTACH_NS);
+                }
+            };
+
+            SizeData sizeData = getSizeData(parent.getResources());
+            view.setMinimumWidth(sizeData.innerItemWidth);
+            view.setMinimumHeight(sizeData.innerItemHeight);
+
+            GradientDrawable bg = new GradientDrawable();
+            bg.setCornerRadius(10 * density);
+            bg.setColor(Color.BLACK);
+            final int pad = (int)(10 * density);
+            view.setPadding(pad, pad, pad, pad);
+            view.setBackgroundDrawable(new InsetDrawable(bg, pad));
+            RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(view) {};
+
+            while (System.nanoTime() - start < INNER_ITEM_CREATE_NS);
+            return holder;
+        }
+
+        @Override
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+            final long start = System.nanoTime();
+            while (System.nanoTime() - start < INNER_ITEM_BIND_NS);
+        }
+
+        @Override
+        public int getItemCount() { return INNER_ITEM_COUNT; }
+    }
+
+    private class OuterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+        static final int TYPE_HEADER = 0;
+        static final int TYPE_RECYCLER = 1;
+
+        ArrayList<InnerAdapter> mAdapters = new ArrayList<>();
+        RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool();
+
+        OuterAdapter() {
+            for (int i = 0; i < OUTER_ITEM_COUNT; i++) {
+                mAdapters.add(new InnerAdapter());
+            }
+        }
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            SizeData sizeData = getSizeData(parent.getResources());
+            if (viewType == TYPE_HEADER) {
+                View view = new View(parent.getContext());
+                view.setMinimumHeight(sizeData.headerHeight);
+                return new RecyclerView.ViewHolder(view) {};
+            } else {
+                final long start = System.nanoTime();
+
+                RecyclerView rv = new RecyclerView(parent.getContext()) {
+                    @Override
+                    protected void onAttachedToWindow() {
+                        final long start = System.nanoTime();
+                        super.onAttachedToWindow();
+                        while (System.nanoTime() - start < OUTER_ITEM_ATTACH_NS);
+
+                    }
+                };
+
+                rv.setLayoutParams(new RecyclerView.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT, sizeData.innerItemHeight));
+                rv.setLayoutManager(new LinearLayoutManager(parent.getContext(),
+                        LinearLayoutManager.HORIZONTAL, false));
+                rv.setRecycledViewPool(mSharedPool);
+                RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(rv) {};
+
+                while (System.nanoTime() - start < OUTER_ITEM_CREATE_NS);
+                return holder;
+            }
+        }
+
+        @Override
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+            if (getItemViewType(position) == TYPE_RECYCLER) {
+                final long start = System.nanoTime();
+                ((RecyclerView)holder.itemView).setAdapter(mAdapters.get(position));
+                while (System.nanoTime() - start < OUTER_ITEM_BIND_NS);
+            }
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            return position == 0 ? TYPE_HEADER : TYPE_RECYCLER;
+        }
+
+        @Override
+        public int getItemCount() {
+            return mAdapters.size();
+        }
+    }
+}