OSDN Git Service

DO NOT MERGE. Cherrypick UiBench from Master
authorKevin Neas <kneas@google.com>
Thu, 12 Nov 2015 20:17:26 +0000 (12:17 -0800)
committerKevin Neas <kneas@google.com>
Fri, 13 Nov 2015 01:09:58 +0000 (01:09 +0000)
UiBench apk for Jank tests for Emerald

Change-Id: Ib58a2b8ff76b18b9c41cbd513c8a16571b7a37a0

44 files changed:
tests/UiBench/.gitignore [new file with mode: 0644]
tests/UiBench/Android.mk [new file with mode: 0644]
tests/UiBench/AndroidManifest.xml [new file with mode: 0644]
tests/UiBench/build.gradle [new file with mode: 0644]
tests/UiBench/gradle/wrapper/gradle-wrapper.jar [new file with mode: 0644]
tests/UiBench/gradle/wrapper/gradle-wrapper.properties [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/ball.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/block.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/ducky.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/frantic.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/jellies.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/large_photo.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/mug.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/pencil.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/scissors.jpg [new file with mode: 0644]
tests/UiBench/res/drawable-nodpi/woot.jpg [new file with mode: 0644]
tests/UiBench/res/layout/activity_bitmap_upload.xml [new file with mode: 0644]
tests/UiBench/res/layout/activity_invalidate.xml [new file with mode: 0644]
tests/UiBench/res/layout/activity_transition.xml [new file with mode: 0644]
tests/UiBench/res/layout/activity_transition_details.xml [new file with mode: 0644]
tests/UiBench/res/layout/card_row.xml [new file with mode: 0644]
tests/UiBench/res/layout/invalidate_row.xml [new file with mode: 0644]
tests/UiBench/res/layout/recycler_view.xml [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/ActivityTransition.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/ActivityTransitionDetails.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/DialogListActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/MainActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/TextUtils.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/TrivialRecyclerViewActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/opengl/ImageFlipRenderThread.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/recyclerview/RvArrayAdapter.java [new file with mode: 0644]
tests/UiBench/src/com/android/test/uibench/recyclerview/RvCompatListActivity.java [new file with mode: 0644]

diff --git a/tests/UiBench/.gitignore b/tests/UiBench/.gitignore
new file mode 100644 (file)
index 0000000..c39eac2
--- /dev/null
@@ -0,0 +1,5 @@
+.gradle
+.idea
+*.iml
+build
+local.properties
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
new file mode 100644 (file)
index 0000000..0e678cd
--- /dev/null
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# omit gradle 'build' dir
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+# use appcompat/support lib from the tree, so improvements/
+# regressions are reflected in test data
+LOCAL_RESOURCE_DIR := \
+    $(LOCAL_PATH)/res \
+    frameworks/support/v7/appcompat/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.recyclerview
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-v4 \
+    android-support-v7-appcompat \
+    android-support-v7-cardview \
+    android-support-v7-recyclerview
+
+LOCAL_PACKAGE_NAME := UiBench
+
+include $(BUILD_PACKAGE)
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..7b4f01c
--- /dev/null
@@ -0,0 +1,165 @@
+<!--
+  ~ 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
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.test.uibench">
+
+    <application
+        android:allowBackup="false"
+        android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
+        tools:ignore="MissingApplicationIcon">
+        <uses-library android:name="android.test.runner" />
+
+        <!-- Root navigation activity -->
+        <activity
+            android:name=".MainActivity"
+            android:label="UiBench">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- General -->
+        <activity
+            android:name=".DialogListActivity"
+            android:label="General/Dialog List" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".GlTextureViewActivity"
+            android:label="General/GL TextureView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".FullscreenOverdrawActivity"
+            android:label="General/Fullscreen Overdraw" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".InvalidateActivity"
+            android:label="General/Invalidate" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TrivialAnimationActivity"
+            android:label="General/Trivial Animation" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TrivialListActivity"
+            android:label="General/Trivial ListView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <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
+            android:name=".BitmapUploadActivity"
+            android:label="Rendering/Bitmap Upload" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ShadowGridActivity"
+            android:label="Rendering/Shadow Grid" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+
+        <!-- Inflation -->
+        <activity
+            android:name=".InflatingListActivity"
+            android:label="Inflation/Inflating ListView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+
+        <!-- Text -->
+        <activity
+            android:name=".EditTextTypeActivity"
+            android:label="Text/EditText Typing" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TextCacheLowHitrateActivity"
+            android:label="Text/Layout Cache Low Hitrate" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TextCacheHighHitrateActivity"
+            android:label="Text/Layout Cache High Hitrate" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/UiBench/build.gradle b/tests/UiBench/build.gradle
new file mode 100644 (file)
index 0000000..0756a8a
--- /dev/null
@@ -0,0 +1,39 @@
+buildscript {
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:1.3.0'
+
+    }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 23
+    buildToolsVersion "22.0.0"
+
+    defaultConfig {
+        minSdkVersion 14
+        targetSdkVersion 23
+        versionCode 1
+        versionName "1.0"
+    }
+
+    sourceSets {
+        main {
+            manifest.srcFile 'AndroidManifest.xml'
+            java.srcDirs = ['src']
+            res.srcDirs = ['res']
+        }
+    }
+}
+
+dependencies {
+    // Dependencies enumerated specifically for platform-independent / reproducible builds.
+    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/gradle/wrapper/gradle-wrapper.jar b/tests/UiBench/gradle/wrapper/gradle-wrapper.jar
new file mode 100644 (file)
index 0000000..8c0fb64
Binary files /dev/null and b/tests/UiBench/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/tests/UiBench/gradle/wrapper/gradle-wrapper.properties b/tests/UiBench/gradle/wrapper/gradle-wrapper.properties
new file mode 100644 (file)
index 0000000..12582f8
--- /dev/null
@@ -0,0 +1,6 @@
+#Wed Aug 26 10:51:13 PDT 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
diff --git a/tests/UiBench/res/drawable-nodpi/ball.jpg b/tests/UiBench/res/drawable-nodpi/ball.jpg
new file mode 100644 (file)
index 0000000..2960b73
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/ball.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/block.jpg b/tests/UiBench/res/drawable-nodpi/block.jpg
new file mode 100644 (file)
index 0000000..04c22a0
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/block.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/ducky.jpg b/tests/UiBench/res/drawable-nodpi/ducky.jpg
new file mode 100644 (file)
index 0000000..830bbe3
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/ducky.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/frantic.jpg b/tests/UiBench/res/drawable-nodpi/frantic.jpg
new file mode 100644 (file)
index 0000000..4c62333
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/frantic.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/jellies.jpg b/tests/UiBench/res/drawable-nodpi/jellies.jpg
new file mode 100644 (file)
index 0000000..ee2b5c6
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/jellies.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/large_photo.jpg b/tests/UiBench/res/drawable-nodpi/large_photo.jpg
new file mode 100644 (file)
index 0000000..e23dbb0
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/large_photo.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/mug.jpg b/tests/UiBench/res/drawable-nodpi/mug.jpg
new file mode 100644 (file)
index 0000000..e149e19
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/mug.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/pencil.jpg b/tests/UiBench/res/drawable-nodpi/pencil.jpg
new file mode 100644 (file)
index 0000000..e348311
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/pencil.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/scissors.jpg b/tests/UiBench/res/drawable-nodpi/scissors.jpg
new file mode 100644 (file)
index 0000000..caf0ce8
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/scissors.jpg differ
diff --git a/tests/UiBench/res/drawable-nodpi/woot.jpg b/tests/UiBench/res/drawable-nodpi/woot.jpg
new file mode 100644 (file)
index 0000000..ccaef67
Binary files /dev/null and b/tests/UiBench/res/drawable-nodpi/woot.jpg differ
diff --git a/tests/UiBench/res/layout/activity_bitmap_upload.xml b/tests/UiBench/res/layout/activity_bitmap_upload.xml
new file mode 100644 (file)
index 0000000..70faa07
--- /dev/null
@@ -0,0 +1,52 @@
+<?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:id="@+id/upload_root"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="10dp"
+    android:clipToPadding="false">
+    <android.support.v7.widget.CardView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+        <view class="com.android.test.uibench.BitmapUploadActivity$UploadView"
+            android:id="@+id/upload_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </android.support.v7.widget.CardView>
+
+    <android.support.v4.widget.Space
+        android:layout_height="10dp"
+        android:layout_width="match_parent" />
+
+    <android.support.v7.widget.CardView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <android.support.v4.widget.Space
+        android:layout_height="10dp"
+        android:layout_width="match_parent" />
+
+    <android.support.v7.widget.CardView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_invalidate.xml b/tests/UiBench/res/layout/activity_invalidate.xml
new file mode 100644 (file)
index 0000000..34bcca9
--- /dev/null
@@ -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:id="@+id/invalidate_root"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml
new file mode 100644 (file)
index 0000000..d4c6610
--- /dev/null
@@ -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 (file)
index 0000000..1022d2f
--- /dev/null
@@ -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/card_row.xml b/tests/UiBench/res/layout/card_row.xml
new file mode 100644 (file)
index 0000000..215f9df
--- /dev/null
@@ -0,0 +1,45 @@
+<?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:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="100dp"
+    android:paddingStart="10dp"
+    android:paddingEnd="10dp"
+    android:paddingTop="5dp"
+    android:paddingBottom="5dp"
+    android:clipToPadding="false"
+    android:background="@null">
+    <android.support.v7.widget.CardView
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+        <TextView
+            android:id="@+id/card_text"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </android.support.v7.widget.CardView>
+
+    <android.support.v4.widget.Space
+        android:layout_height="match_parent"
+        android:layout_width="10dp" />
+
+    <android.support.v7.widget.CardView
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/invalidate_row.xml b/tests/UiBench/res/layout/invalidate_row.xml
new file mode 100644 (file)
index 0000000..9feefde
--- /dev/null
@@ -0,0 +1,84 @@
+<?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:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="0dp"
+    android:layout_weight="1">
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+</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 (file)
index 0000000..54c5b58
--- /dev/null
@@ -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 (file)
index 0000000..1106a13
--- /dev/null
@@ -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 (file)
index 0000000..a654c61
--- /dev/null
@@ -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/BitmapUploadActivity.java b/tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java
new file mode 100644 (file)
index 0000000..e2bf897
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+public class BitmapUploadActivity extends AppCompatActivity {
+    public static class UploadView extends View {
+        private int mColorValue;
+        private Bitmap mBitmap;
+        private final DisplayMetrics mMetrics = new DisplayMetrics();
+        private final Rect mRect = new Rect();
+
+        public UploadView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @SuppressWarnings("unused")
+        public void setColorValue(int colorValue) {
+            if (colorValue == mColorValue) return;
+
+            mColorValue = colorValue;
+
+            // modify the bitmap's color to ensure it's uploaded to the GPU
+            mBitmap.eraseColor(Color.rgb(mColorValue, 255 - mColorValue, 255));
+
+            invalidate();
+        }
+
+        @Override
+        protected void onAttachedToWindow() {
+            super.onAttachedToWindow();
+
+            getDisplay().getMetrics(mMetrics);
+            int minDisplayDimen = Math.min(mMetrics.widthPixels, mMetrics.heightPixels);
+            int bitmapSize = Math.min((int) (minDisplayDimen * 0.75), 720);
+            if (mBitmap == null
+                    || mBitmap.getWidth() != bitmapSize
+                    || mBitmap.getHeight() != bitmapSize) {
+                mBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
+            }
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            if (mBitmap != null) {
+                mRect.set(0, 0, getWidth(), getHeight());
+                canvas.drawBitmap(mBitmap, null, mRect, null);
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_bitmap_upload);
+
+        // animate color to force bitmap uploads
+        UploadView uploadView = (UploadView) findViewById(R.id.upload_view);
+        ObjectAnimator colorValueAnimator = ObjectAnimator.ofInt(uploadView, "colorValue", 0, 255);
+        colorValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
+        colorValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        colorValueAnimator.start();
+
+        // animate scene root to guarantee there's a minimum amount of GPU rendering work
+        View uploadRoot = findViewById(R.id.upload_root);
+        ObjectAnimator yAnimator = ObjectAnimator.ofFloat(uploadRoot, "translationY", 0, 100);
+        yAnimator.setRepeatMode(ValueAnimator.REVERSE);
+        yAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        yAnimator.start();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
new file mode 100644 (file)
index 0000000..fe712d5
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class DialogListActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ListView listView = new ListView(this);
+        listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildSimpleStringList()));
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle("Dialog");
+        builder.setView(listView);
+        builder.create().show();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java b/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java
new file mode 100644 (file)
index 0000000..08ab510
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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.Instrumentation;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.support.v7.app.AppCompatActivity;
+import android.view.KeyEvent;
+import android.widget.EditText;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * Note: currently incomplete, complexity of input continuously grows, instead of looping
+ * over a stable amount of work.
+ *
+ * Simulates typing continuously into an EditText.
+ */
+public class EditTextTypeActivity extends AppCompatActivity {
+    Thread mThread;
+
+    private static String sSeedText = "";
+    static {
+        final int count = 100;
+        final String string = "hello ";
+
+        StringBuilder builder = new StringBuilder(count * string.length());
+        for (int i = 0; i < count; i++) {
+            builder.append(string);
+        }
+        sSeedText = builder.toString();
+    }
+
+    final Object mLock = new Object();
+    boolean mShouldStop = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        EditText editText = new EditText(this);
+        editText.setText(sSeedText);
+        setContentView(editText);
+
+        final Instrumentation instrumentation = new Instrumentation();
+        final Semaphore sem = new Semaphore(0);
+        MessageQueue.IdleHandler handler = new MessageQueue.IdleHandler() {
+            @Override
+            public boolean queueIdle() {
+                // TODO: consider other signaling approaches
+                sem.release();
+                return true;
+            }
+        };
+        Looper.myQueue().addIdleHandler(handler);
+        synchronized (mLock) {
+            mShouldStop = false;
+        }
+        mThread = new Thread(new Runnable() {
+            int codes[] = { KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_L,
+                    KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_SPACE };
+            int i = 0;
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        sem.acquire();
+                    } catch (InterruptedException e) {
+                        // TODO, maybe
+                    }
+                    int code = codes[i % codes.length];
+                    if (i % 100 == 99) code = KeyEvent.KEYCODE_ENTER;
+
+                    synchronized (mLock) {
+                        if (mShouldStop) break;
+                    }
+
+                    // TODO: bit of a race here, since the event can arrive after pause/stop.
+                    // (Can't synchronize on key send, since it's synchronous.)
+                    instrumentation.sendKeyDownUpSync(code);
+                    i++;
+                }
+            }
+        });
+        mThread.start();
+    }
+
+    @Override
+    protected void onPause() {
+        synchronized (mLock) {
+            mShouldStop = true;
+        }
+        super.onPause();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java b/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java
new file mode 100644 (file)
index 0000000..f1ecc56
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+/**
+ * Draws hundreds of levels of overdraw over the content area.
+ *
+ * This should all be optimized out by the renderer.
+ */
+public class FullscreenOverdrawActivity extends AppCompatActivity {
+    private class OverdrawView extends View {
+        Paint paint = new Paint();
+        int mColorValue = 0;
+
+        public OverdrawView(Context context) {
+            super(context);
+        }
+
+        @SuppressWarnings("unused")
+        public void setColorValue(int colorValue) {
+            mColorValue = colorValue;
+            invalidate();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            paint.setColor(Color.rgb(mColorValue, 255 - mColorValue, 255));
+
+            for (int i = 0; i < 400; i++) {
+                canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
+            }
+        }
+    }
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        OverdrawView overdrawView = new OverdrawView(this);
+        setContentView(overdrawView);
+
+        ObjectAnimator objectAnimator = ObjectAnimator.ofInt(overdrawView, "colorValue", 0, 255);
+        objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
+        objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        objectAnimator.start();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java b/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java
new file mode 100644 (file)
index 0000000..a12742d
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.test.uibench.opengl.ImageFlipRenderThread;
+
+public class GlTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
+    private ImageFlipRenderThread mRenderThread;
+    private TextureView mTextureView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mTextureView = new TextureView(this);
+        mTextureView.setSurfaceTextureListener(this);
+        setContentView(mTextureView, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
+                Gravity.CENTER));
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        mRenderThread = new ImageFlipRenderThread(getResources(), surface);
+        mRenderThread.start();
+
+        mTextureView.setCameraDistance(5000);
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+        animator.setRepeatMode(ObjectAnimator.REVERSE);
+        animator.setRepeatCount(ObjectAnimator.INFINITE);
+        animator.setDuration(4000);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mTextureView.invalidate();
+            }
+        });
+        animator.start();
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        mRenderThread.finish();
+        try {
+            mRenderThread.join();
+        } catch (InterruptedException e) {
+            Log.e(ImageFlipRenderThread.LOG_TAG, "Could not wait for render thread");
+        }
+        return true;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+    }
+
+}
\ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
new file mode 100644 (file)
index 0000000..603244e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import com.android.test.uibench.listview.CompatListActivity;
+
+public class InflatingListActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, TextUtils.buildSimpleStringList()) {
+            @Override
+            public View getView(int position, View convertView, ViewGroup parent) {
+                // pathological getView behavior: drop convertView on the floor to force inflation
+                return super.getView(position, null, parent);
+            }
+        };
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java b/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java
new file mode 100644 (file)
index 0000000..93d67a6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.v7.app.AppCompatActivity;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Tests invalidation performance by invalidating a large number of easily rendered views,
+ */
+public class InvalidateActivity extends AppCompatActivity {
+    public static class ColorView extends View {
+        @ColorInt
+        public int mColor;
+
+        public ColorView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public void setColor(@ColorInt int color) {
+            mColor = color;
+            invalidate();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            canvas.drawColor(mColor);
+        }
+    }
+
+    ColorView[][] mColorViews;
+
+    @SuppressWarnings("unused")
+    public void setColorValue(int colorValue) {
+        @ColorInt int a = Color.rgb(colorValue, 255 - colorValue, 255);
+        @ColorInt int b = Color.rgb(255, colorValue, 255 - colorValue);
+        for (int y = 0; y < mColorViews.length; y++) {
+            for (int x = 0; x < mColorViews[y].length; x++) {
+                mColorViews[y][x].setColor((x + y) % 2 == 0 ? a : b);
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_invalidate);
+
+        ViewGroup root = (ViewGroup) findViewById(R.id.invalidate_root);
+        for (int y = 0; y < root.getChildCount(); y++) {
+            ViewGroup row = (ViewGroup) root.getChildAt(y);
+            if (mColorViews == null) {
+                mColorViews = new ColorView[root.getChildCount()][row.getChildCount()];
+            }
+
+            for (int x = 0; x < row.getChildCount(); x++) {
+                mColorViews[y][x] = (ColorView) row.getChildAt(x);
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofInt(this, "colorValue", 0, 255);
+        animator.setRepeatMode(ValueAnimator.REVERSE);
+        animator.setRepeatCount(ValueAnimator.INFINITE);
+        animator.start();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/MainActivity.java b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
new file mode 100644 (file)
index 0000000..2111274
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MainActivity extends AppCompatActivity {
+    private static final String EXTRA_PATH = "activity_path";
+    private static final String CATEGORY_HWUI_TEST = "com.android.test.uibench.TEST";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+        String path = intent.getStringExtra(EXTRA_PATH);
+
+        if (path == null) {
+            path = "";
+        } else {
+            // not root level, display where we are in the hierarchy
+            setTitle(path);
+        }
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            ListFragment listFragment = new ListFragment() {
+                @Override
+                @SuppressWarnings("unchecked")
+                public void onListItemClick(ListView l, View v, int position, long id) {
+                    Map<String, Object> map = (Map<String, Object>)l.getItemAtPosition(position);
+
+                    Intent intent = (Intent) map.get("intent");
+                    startActivity(intent);
+                }
+
+                @Override
+                public void onViewCreated(View view, Bundle savedInstanceState) {
+                    super.onViewCreated(view, savedInstanceState);
+                    getListView().setTextFilterEnabled(true);
+                }
+            };
+            listFragment.setListAdapter(new SimpleAdapter(this, getData(path),
+                    android.R.layout.simple_list_item_1, new String[] { "title" },
+                    new int[] { android.R.id.text1 }));
+            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+        }
+    }
+
+    protected List<Map<String, Object>> getData(String prefix) {
+        List<Map<String, Object>> myData = new ArrayList<>();
+
+        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+        mainIntent.addCategory(CATEGORY_HWUI_TEST);
+
+        PackageManager pm = getPackageManager();
+        List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
+
+        if (null == list)
+            return myData;
+
+        String[] prefixPath;
+        String prefixWithSlash = prefix;
+
+        if (prefix.equals("")) {
+            prefixPath = null;
+        } else {
+            prefixPath = prefix.split("/");
+            prefixWithSlash = prefix + "/";
+        }
+
+        int len = list.size();
+
+        Map<String, Boolean> entries = new HashMap<>();
+
+        for (int i = 0; i < len; i++) {
+            ResolveInfo info = list.get(i);
+            CharSequence labelSeq = info.loadLabel(pm);
+            String label = labelSeq != null
+                    ? labelSeq.toString()
+                    : info.activityInfo.name;
+
+            if (prefixWithSlash.length() == 0 || label.startsWith(prefixWithSlash)) {
+
+                String[] labelPath = label.split("/");
+
+                String nextLabel = prefixPath == null ? labelPath[0] : labelPath[prefixPath.length];
+
+                if ((prefixPath != null ? prefixPath.length : 0) == labelPath.length - 1) {
+                    addItem(myData, nextLabel, activityIntent(
+                            info.activityInfo.applicationInfo.packageName,
+                            info.activityInfo.name));
+                } else {
+                    if (entries.get(nextLabel) == null) {
+                        addItem(myData, nextLabel, browseIntent(prefix.equals("") ?
+                                nextLabel : prefix + "/" + nextLabel));
+                        entries.put(nextLabel, true);
+                    }
+                }
+            }
+        }
+
+        Collections.sort(myData, sDisplayNameComparator);
+
+        return myData;
+    }
+
+    private final static Comparator<Map<String, Object>> sDisplayNameComparator =
+            new Comparator<Map<String, Object>>() {
+                private final Collator collator = Collator.getInstance();
+
+                public int compare(Map<String, Object> map1, Map<String, Object> map2) {
+                    return collator.compare(map1.get("title"), map2.get("title"));
+                }
+            };
+
+    protected Intent activityIntent(String pkg, String componentName) {
+        Intent result = new Intent();
+        result.setClassName(pkg, componentName);
+        return result;
+    }
+
+    protected Intent browseIntent(String path) {
+        Intent result = new Intent();
+        result.setClass(this, MainActivity.class);
+        result.putExtra(EXTRA_PATH, path);
+        return result;
+    }
+
+    protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {
+        Map<String, Object> temp = new HashMap<>();
+        temp.put("title", name);
+        temp.put("intent", intent);
+        data.add(temp);
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
new file mode 100644 (file)
index 0000000..d32f071
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ArrayAdapter;
+
+public class ShadowGridActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            ListFragment listFragment = new ListFragment() {
+                @Override
+                public void onViewCreated(View view, Bundle savedInstanceState) {
+                    super.onViewCreated(view, savedInstanceState);
+                    getListView().setDivider(null);
+                }
+            };
+
+            listFragment.setListAdapter(new ArrayAdapter<>(this,
+                    R.layout.card_row, R.id.card_text, TextUtils.buildSimpleStringList()));
+            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+        }
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
new file mode 100644 (file)
index 0000000..fc5be35
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import com.android.test.uibench.listview.CompatListActivity;
+
+public class TextCacheHighHitrateActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildParagraphListWithHitPercentage(80));
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
new file mode 100644 (file)
index 0000000..14dc437
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import com.android.test.uibench.listview.CompatListActivity;
+
+public class TextCacheLowHitrateActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildParagraphListWithHitPercentage(20));
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextUtils.java b/tests/UiBench/src/com/android/test/uibench/TextUtils.java
new file mode 100644 (file)
index 0000000..d88ca1e
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 java.util.Random;
+
+public class TextUtils {
+    private static final int STRING_COUNT = 200;
+    private static final int SIMPLE_STRING_LENGTH = 10;
+
+    /**
+     * Create word of random assortment of lower/upper case letters
+     */
+    private static String randomWord(Random random, int length) {
+        String result = "";
+        for (int j = 0; j < length; j++) {
+            // add random letter
+            int base = random.nextInt(2) == 0 ? 'A' : 'a';
+            result += (char)(random.nextInt(26) + base);
+        }
+        return result;
+    }
+
+    public static String[] buildSimpleStringList() {
+        String[] strings = new String[STRING_COUNT];
+        Random random = new Random(0);
+        for (int i = 0; i < strings.length; i++) {
+            strings[i] = randomWord(random, SIMPLE_STRING_LENGTH);
+        }
+        return strings;
+    }
+
+    // a small number of strings reused frequently, expected to hit
+    // in the word-granularity text layout cache
+    static final String[] CACHE_HIT_STRINGS = new String[] {
+            "a",
+            "small",
+            "number",
+            "of",
+            "strings",
+            "reused",
+            "frequently"
+    };
+
+    private static final int WORDS_IN_PARAGRAPH = 150;
+
+    // misses are fairly long 'words' to ensure they miss
+    private static final int PARAGRAPH_MISS_MIN_LENGTH = 4;
+    private static final int PARAGRAPH_MISS_MAX_LENGTH = 9;
+
+    static String[] buildParagraphListWithHitPercentage(int hitPercentage) {
+        if (hitPercentage < 0 || hitPercentage > 100) throw new IllegalArgumentException();
+
+        String[] strings = new String[STRING_COUNT];
+        Random random = new Random(0);
+        for (int i = 0; i < strings.length; i++) {
+            String result = "";
+            for (int word = 0; word < WORDS_IN_PARAGRAPH; word++) {
+                if (word != 0) {
+                    result += " ";
+                }
+                if (random.nextInt(100) < hitPercentage) {
+                    // add a common word, which is very likely to hit in the cache
+                    result += CACHE_HIT_STRINGS[random.nextInt(CACHE_HIT_STRINGS.length)];
+                } else {
+                    // construct a random word, which will *most likely* miss
+                    int length = PARAGRAPH_MISS_MIN_LENGTH;
+                    length += random.nextInt(PARAGRAPH_MISS_MAX_LENGTH - PARAGRAPH_MISS_MIN_LENGTH);
+
+                    result += randomWord(random, length);
+                }
+            }
+            strings[i] = result;
+        }
+
+        return strings;
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivity.java
new file mode 100644 (file)
index 0000000..6e98472
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+public class TrivialAnimationActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new ColorDrawable() {
+            int colorValue = 0;
+            int colorDelta = 1;
+
+            @Override
+            public void draw(Canvas canvas) {
+                colorValue += colorDelta;
+                if (colorValue == 255 || colorValue == 0) {
+                    colorDelta *= -1;
+                }
+
+                setColor(Color.rgb(255, colorValue, 255 - colorValue));
+                invalidateSelf();
+                super.draw(canvas);
+            }
+        });
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
new file mode 100644 (file)
index 0000000..2625a99
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import com.android.test.uibench.listview.CompatListActivity;
+
+public class TrivialListActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildSimpleStringList());
+    }
+}
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 (file)
index 0000000..4647ba7
--- /dev/null
@@ -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/listview/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/listview/CompatListActivity.java
new file mode 100644 (file)
index 0000000..214c074
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.listview;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ListAdapter;
+
+public abstract class CompatListActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            ListFragment listFragment = new ListFragment();
+            listFragment.setListAdapter(createListAdapter());
+            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+        }
+    }
+
+    protected abstract ListAdapter createListAdapter();
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/opengl/ImageFlipRenderThread.java b/tests/UiBench/src/com/android/test/uibench/opengl/ImageFlipRenderThread.java
new file mode 100644 (file)
index 0000000..119ce52
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * 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.opengl;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLUtils;
+import android.util.Log;
+
+import com.android.test.uibench.R;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
+import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.GL_COMPILE_STATUS;
+import static android.opengl.GLES20.GL_FLOAT;
+import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
+import static android.opengl.GLES20.GL_LINEAR;
+import static android.opengl.GLES20.GL_LINK_STATUS;
+import static android.opengl.GLES20.GL_NO_ERROR;
+import static android.opengl.GLES20.GL_RGBA;
+import static android.opengl.GLES20.GL_TEXTURE0;
+import static android.opengl.GLES20.GL_TEXTURE_2D;
+import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
+import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
+import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
+import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
+import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
+import static android.opengl.GLES20.GL_TRUE;
+import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
+import static android.opengl.GLES20.GL_VERTEX_SHADER;
+import static android.opengl.GLES20.glActiveTexture;
+import static android.opengl.GLES20.glAttachShader;
+import static android.opengl.GLES20.glBindTexture;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+import static android.opengl.GLES20.glCompileShader;
+import static android.opengl.GLES20.glCreateProgram;
+import static android.opengl.GLES20.glCreateShader;
+import static android.opengl.GLES20.glDeleteProgram;
+import static android.opengl.GLES20.glDeleteShader;
+import static android.opengl.GLES20.glDrawArrays;
+import static android.opengl.GLES20.glEnableVertexAttribArray;
+import static android.opengl.GLES20.glGenTextures;
+import static android.opengl.GLES20.glGetAttribLocation;
+import static android.opengl.GLES20.glGetError;
+import static android.opengl.GLES20.glGetProgramInfoLog;
+import static android.opengl.GLES20.glGetProgramiv;
+import static android.opengl.GLES20.glGetShaderInfoLog;
+import static android.opengl.GLES20.glGetShaderiv;
+import static android.opengl.GLES20.glGetUniformLocation;
+import static android.opengl.GLES20.glLinkProgram;
+import static android.opengl.GLES20.glShaderSource;
+import static android.opengl.GLES20.glTexParameteri;
+import static android.opengl.GLES20.glUniform1i;
+import static android.opengl.GLES20.glUseProgram;
+import static android.opengl.GLES20.glVertexAttribPointer;
+
+public class ImageFlipRenderThread extends Thread {
+    public static final String LOG_TAG = "GLTextureView";
+
+    static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+    static final int EGL_OPENGL_ES2_BIT = 4;
+
+    private volatile boolean mFinished;
+
+    private final Resources mResources;
+    private final SurfaceTexture mSurface;
+
+    private EGL10 mEgl;
+    private EGLDisplay mEglDisplay;
+    private EGLConfig mEglConfig;
+    private EGLContext mEglContext;
+    private EGLSurface mEglSurface;
+
+    public ImageFlipRenderThread(Resources resources, SurfaceTexture surface) {
+        mResources = resources;
+        mSurface = surface;
+    }
+
+    private static final String sSimpleVS =
+            "attribute vec4 position;\n" +
+                    "attribute vec2 texCoords;\n" +
+                    "varying vec2 outTexCoords;\n" +
+                    "\nvoid main(void) {\n" +
+                    "    outTexCoords = texCoords;\n" +
+                    "    gl_Position = position;\n" +
+                    "}\n\n";
+    private static final String sSimpleFS =
+            "precision mediump float;\n\n" +
+                    "varying vec2 outTexCoords;\n" +
+                    "uniform sampler2D texture;\n" +
+                    "\nvoid main(void) {\n" +
+                    "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
+                    "}\n\n";
+
+    private static final int FLOAT_SIZE_BYTES = 4;
+    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+    private final float[] mTriangleVerticesData = {
+            // X, Y, Z, U, V
+            -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
+            1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+            -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+            1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
+    };
+
+    @Override
+    public void run() {
+        initGL();
+
+        FloatBuffer triangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
+                * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
+        triangleVertices.put(mTriangleVerticesData).position(0);
+
+        int texture = loadTexture(R.drawable.large_photo);
+        int program = buildProgram(sSimpleVS, sSimpleFS);
+
+        int attribPosition = glGetAttribLocation(program, "position");
+        checkGlError();
+
+        int attribTexCoords = glGetAttribLocation(program, "texCoords");
+        checkGlError();
+
+        int uniformTexture = glGetUniformLocation(program, "texture");
+        checkGlError();
+
+        glBindTexture(GL_TEXTURE_2D, texture);
+        checkGlError();
+
+        glUseProgram(program);
+        checkGlError();
+
+        glEnableVertexAttribArray(attribPosition);
+        checkGlError();
+
+        glEnableVertexAttribArray(attribTexCoords);
+        checkGlError();
+
+        glUniform1i(uniformTexture, 0);
+        checkGlError();
+
+        // drawQuad
+        triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+        glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
+                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+        checkGlError();
+
+        triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+        glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
+                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+        checkGlError();
+
+        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+        checkGlError();
+
+        while (!mFinished) {
+            checkCurrent();
+
+            glClear(GL_COLOR_BUFFER_BIT);
+            checkGlError();
+
+            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+            checkGlError();
+
+            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                throw new RuntimeException("Cannot swap buffers");
+            }
+            checkEglError();
+
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+        }
+
+        finishGL();
+    }
+
+    private int loadTexture(int resource) {
+        int[] textures = new int[1];
+
+        glActiveTexture(GL_TEXTURE0);
+        glGenTextures(1, textures, 0);
+        checkGlError();
+
+        int texture = textures[0];
+        glBindTexture(GL_TEXTURE_2D, texture);
+        checkGlError();
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+        Bitmap bitmap = BitmapFactory.decodeResource(mResources, resource);
+
+        GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
+        checkGlError();
+
+        bitmap.recycle();
+
+        return texture;
+    }
+
+    private static int buildProgram(String vertex, String fragment) {
+        int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+        if (vertexShader == 0) return 0;
+
+        int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+        if (fragmentShader == 0) return 0;
+
+        int program = glCreateProgram();
+        glAttachShader(program, vertexShader);
+        checkGlError();
+
+        glAttachShader(program, fragmentShader);
+        checkGlError();
+
+        glLinkProgram(program);
+        checkGlError();
+
+        int[] status = new int[1];
+        glGetProgramiv(program, GL_LINK_STATUS, status, 0);
+        if (status[0] != GL_TRUE) {
+            String error = glGetProgramInfoLog(program);
+            Log.d(LOG_TAG, "Error while linking program:\n" + error);
+            glDeleteShader(vertexShader);
+            glDeleteShader(fragmentShader);
+            glDeleteProgram(program);
+            return 0;
+        }
+
+        return program;
+    }
+
+    private static int buildShader(String source, int type) {
+        int shader = glCreateShader(type);
+
+        glShaderSource(shader, source);
+        checkGlError();
+
+        glCompileShader(shader);
+        checkGlError();
+
+        int[] status = new int[1];
+        glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
+        if (status[0] != GL_TRUE) {
+            String error = glGetShaderInfoLog(shader);
+            Log.d(LOG_TAG, "Error while compiling shader:\n" + error);
+            glDeleteShader(shader);
+            return 0;
+        }
+
+        return shader;
+    }
+
+    private void checkEglError() {
+        int error = mEgl.eglGetError();
+        if (error != EGL10.EGL_SUCCESS) {
+            Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error));
+        }
+    }
+
+    private static void checkGlError() {
+        int error = glGetError();
+        if (error != GL_NO_ERROR) {
+            Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+        }
+    }
+
+    private void finishGL() {
+        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+    }
+
+    private void checkCurrent() {
+        if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
+                !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
+            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                throw new RuntimeException("eglMakeCurrent failed "
+                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+        }
+    }
+
+    private void initGL() {
+        mEgl = (EGL10) EGLContext.getEGL();
+
+        mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+        if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+            throw new RuntimeException("eglGetDisplay failed "
+                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        }
+
+        int[] version = new int[2];
+        if (!mEgl.eglInitialize(mEglDisplay, version)) {
+            throw new RuntimeException("eglInitialize failed " +
+                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        }
+
+        mEglConfig = chooseEglConfig();
+        if (mEglConfig == null) {
+            throw new RuntimeException("eglConfig not initialized");
+        }
+
+        mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+        mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null);
+
+        if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+            int error = mEgl.eglGetError();
+            if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+                Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                return;
+            }
+            throw new RuntimeException("createWindowSurface failed "
+                    + GLUtils.getEGLErrorString(error));
+        }
+
+        if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+            throw new RuntimeException("eglMakeCurrent failed "
+                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        }
+    }
+
+
+    EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+        int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
+        return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+    }
+
+    private EGLConfig chooseEglConfig() {
+        int[] configsCount = new int[1];
+        EGLConfig[] configs = new EGLConfig[1];
+        int[] configSpec = getConfig();
+        if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+            throw new IllegalArgumentException("eglChooseConfig failed " +
+                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        } else if (configsCount[0] > 0) {
+            return configs[0];
+        }
+        return null;
+    }
+
+    private static int[] getConfig() {
+        return new int[]{
+                EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                EGL10.EGL_RED_SIZE, 8,
+                EGL10.EGL_GREEN_SIZE, 8,
+                EGL10.EGL_BLUE_SIZE, 8,
+                EGL10.EGL_ALPHA_SIZE, 8,
+                EGL10.EGL_DEPTH_SIZE, 0,
+                EGL10.EGL_STENCIL_SIZE, 0,
+                EGL10.EGL_NONE
+        };
+    }
+
+    public void finish() {
+        mFinished = true;
+    }
+}
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 (file)
index 0000000..e5a3a49
--- /dev/null
@@ -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 (file)
index 0000000..e08dbc6
--- /dev/null
@@ -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();
+}