1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.test.uibench;
17
18import android.content.Context;
19import android.content.res.Resources;
20import android.graphics.Color;
21import android.graphics.drawable.GradientDrawable;
22import android.graphics.drawable.InsetDrawable;
23import android.support.v7.widget.LinearLayoutManager;
24import android.support.v7.widget.RecyclerView;
25import android.view.View;
26import android.view.ViewGroup;
27
28import com.android.test.uibench.recyclerview.RvCompatListActivity;
29
30import java.util.ArrayList;
31import java.util.concurrent.TimeUnit;
32
33public class SlowNestedRecyclerViewActivity extends RvCompatListActivity {
34    private static final int OUTER_ITEM_COUNT = 100;
35    private static final int INNER_ITEM_COUNT = 20;
36
37    private static final long INNER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(6);
38    private static final long INNER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1);
39    private static final long INNER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1);
40
41    private static final long OUTER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(3);
42    private static final long OUTER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1);
43    private static final long OUTER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1);
44
45    private SizeData mSizeData;
46
47    private static class SizeData {
48        final int innerItemWidth;
49        final int innerItemHeight;
50        final int headerHeight;
51
52        SizeData(Resources resources) {
53            innerItemWidth = (int) (resources.getDisplayMetrics().widthPixels / 3.3f);
54            innerItemHeight = (int) (innerItemWidth * 1.6f);
55            headerHeight = (int) (resources.getDisplayMetrics().heightPixels * 0.5f);
56        }
57    }
58
59    private SizeData getSizeData(Resources resources) {
60        if (mSizeData == null) {
61            mSizeData = new SizeData(resources);
62        }
63        return mSizeData;
64    }
65
66    @Override
67    protected RecyclerView.LayoutManager createLayoutManager(Context context) {
68        return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
69    }
70
71    @Override
72    protected RecyclerView.Adapter createAdapter() {
73        return new OuterAdapter();
74    }
75
76    private class InnerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
77        @Override
78        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
79            final long start = System.nanoTime();
80
81            final float density = parent.getResources().getDisplayMetrics().density;
82            View view = new View(parent.getContext()) {
83                @Override
84                protected void onAttachedToWindow() {
85                    final long start = System.nanoTime();
86                    super.onAttachedToWindow();
87                    while (System.nanoTime() - start < INNER_ITEM_ATTACH_NS);
88                }
89            };
90
91            SizeData sizeData = getSizeData(parent.getResources());
92            view.setMinimumWidth(sizeData.innerItemWidth);
93            view.setMinimumHeight(sizeData.innerItemHeight);
94
95            GradientDrawable bg = new GradientDrawable();
96            bg.setCornerRadius(10 * density);
97            bg.setColor(Color.BLACK);
98            final int pad = (int)(10 * density);
99            view.setPadding(pad, pad, pad, pad);
100            view.setBackgroundDrawable(new InsetDrawable(bg, pad));
101            RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(view) {};
102
103            while (System.nanoTime() - start < INNER_ITEM_CREATE_NS);
104            return holder;
105        }
106
107        @Override
108        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
109            final long start = System.nanoTime();
110            while (System.nanoTime() - start < INNER_ITEM_BIND_NS);
111        }
112
113        @Override
114        public int getItemCount() { return INNER_ITEM_COUNT; }
115    }
116
117    private class OuterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
118        static final int TYPE_HEADER = 0;
119        static final int TYPE_RECYCLER = 1;
120
121        ArrayList<InnerAdapter> mAdapters = new ArrayList<>();
122        RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool();
123
124        OuterAdapter() {
125            for (int i = 0; i < OUTER_ITEM_COUNT; i++) {
126                mAdapters.add(new InnerAdapter());
127            }
128        }
129
130        @Override
131        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
132            SizeData sizeData = getSizeData(parent.getResources());
133            if (viewType == TYPE_HEADER) {
134                View view = new View(parent.getContext());
135                view.setMinimumHeight(sizeData.headerHeight);
136                return new RecyclerView.ViewHolder(view) {};
137            } else {
138                final long start = System.nanoTime();
139
140                RecyclerView rv = new RecyclerView(parent.getContext()) {
141                    @Override
142                    protected void onAttachedToWindow() {
143                        final long start = System.nanoTime();
144                        super.onAttachedToWindow();
145                        while (System.nanoTime() - start < OUTER_ITEM_ATTACH_NS);
146
147                    }
148                };
149
150                rv.setLayoutParams(new RecyclerView.LayoutParams(
151                        ViewGroup.LayoutParams.MATCH_PARENT, sizeData.innerItemHeight));
152                rv.setLayoutManager(new LinearLayoutManager(parent.getContext(),
153                        LinearLayoutManager.HORIZONTAL, false));
154                rv.setRecycledViewPool(mSharedPool);
155                RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(rv) {};
156
157                while (System.nanoTime() - start < OUTER_ITEM_CREATE_NS);
158                return holder;
159            }
160        }
161
162        @Override
163        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
164            if (getItemViewType(position) == TYPE_RECYCLER) {
165                final long start = System.nanoTime();
166                ((RecyclerView)holder.itemView).setAdapter(mAdapters.get(position));
167                while (System.nanoTime() - start < OUTER_ITEM_BIND_NS);
168            }
169        }
170
171        @Override
172        public int getItemViewType(int position) {
173            return position == 0 ? TYPE_HEADER : TYPE_RECYCLER;
174        }
175
176        @Override
177        public int getItemCount() {
178            return mAdapters.size();
179        }
180    }
181}
182