diff --git a/tests/JankBench/Android.mk b/tests/JankBench/Android.mk
new file mode 100644
index 0000000000000..12568a09e71ec
--- /dev/null
+++ b/tests/JankBench/Android.mk
@@ -0,0 +1,38 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MANIFEST_FILE := app/src/main/AndroidManifest.xml
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_USE_AAPT2 := true
+
+# omit gradle 'build' dir
+LOCAL_SRC_FILES := $(call all-java-files-under,app/src/main/java)
+
+# use appcompat/support lib from the tree, so improvements/
+# regressions are reflected in test data
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/app/src/main/res \
+
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+ android-support-design \
+ android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-cardview \
+ android-support-v7-recyclerview \
+ android-support-v17-leanback \
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ apache-commons-math \
+ junit
+
+
+LOCAL_PACKAGE_NAME := JankBench
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/JankBench/app/src/androidTest/java/com/android/benchmark/ApplicationTest.java b/tests/JankBench/app/src/androidTest/java/com/android/benchmark/ApplicationTest.java
new file mode 100644
index 0000000000000..79aff900fd0eb
--- /dev/null
+++ b/tests/JankBench/app/src/androidTest/java/com/android/benchmark/ApplicationTest.java
@@ -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.
+ */
+
+/*
+ * 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.benchmark;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * Testing Fundamentals
+ */
+public class ApplicationTest extends ApplicationTestCase {
+ public ApplicationTest() {
+ super(Application.class);
+ }
+}
diff --git a/tests/JankBench/app/src/main/AndroidManifest.xml b/tests/JankBench/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000..58aa66fcd05d9
--- /dev/null
+++ b/tests/JankBench/app/src/main/AndroidManifest.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/BenchmarkDashboardFragment.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/BenchmarkDashboardFragment.java
new file mode 100644
index 0000000000000..b0a97ae0995bd
--- /dev/null
+++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/BenchmarkDashboardFragment.java
@@ -0,0 +1,40 @@
+/*
+ * 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.benchmark.app;
+
+import android.support.v4.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.benchmark.R;
+
+/**
+ * Fragment for the Benchmark dashboard
+ */
+public class BenchmarkDashboardFragment extends Fragment {
+
+ public BenchmarkDashboardFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_dashboard, container, false);
+ }
+}
diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/BenchmarkListAdapter.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/BenchmarkListAdapter.java
new file mode 100644
index 0000000000000..7419b30814f66
--- /dev/null
+++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/BenchmarkListAdapter.java
@@ -0,0 +1,126 @@
+/*
+ * 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.benchmark.app;
+
+import android.graphics.Typeface;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import com.android.benchmark.registry.BenchmarkGroup;
+import com.android.benchmark.registry.BenchmarkRegistry;
+import com.android.benchmark.R;
+
+/**
+ *
+ */
+public class BenchmarkListAdapter extends BaseExpandableListAdapter {
+
+ private final LayoutInflater mInflater;
+ private final BenchmarkRegistry mRegistry;
+
+ BenchmarkListAdapter(LayoutInflater inflater,
+ BenchmarkRegistry registry) {
+ mInflater = inflater;
+ mRegistry = registry;
+ }
+
+ @Override
+ public int getGroupCount() {
+ return mRegistry.getGroupCount();
+ }
+
+ @Override
+ public int getChildrenCount(int groupPosition) {
+ return mRegistry.getBenchmarkCount(groupPosition);
+ }
+
+ @Override
+ public Object getGroup(int groupPosition) {
+ return mRegistry.getBenchmarkGroup(groupPosition);
+ }
+
+ @Override
+ public Object getChild(int groupPosition, int childPosition) {
+ BenchmarkGroup benchmarkGroup = mRegistry.getBenchmarkGroup(groupPosition);
+
+ if (benchmarkGroup != null) {
+ return benchmarkGroup.getBenchmarks()[childPosition];
+ }
+
+ return null;
+ }
+
+ @Override
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ @Override
+ public long getChildId(int groupPosition, int childPosition) {
+ return childPosition;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return false;
+ }
+
+ @Override
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
+ BenchmarkGroup group = (BenchmarkGroup) getGroup(groupPosition);
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.benchmark_list_group_row, null);
+ }
+
+ TextView title = (TextView) convertView.findViewById(R.id.group_name);
+ title.setTypeface(null, Typeface.BOLD);
+ title.setText(group.getTitle());
+ return convertView;
+ }
+
+ @Override
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ BenchmarkGroup.Benchmark benchmark =
+ (BenchmarkGroup.Benchmark) getChild(groupPosition, childPosition);
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.benchmark_list_item, null);
+ }
+
+ TextView name = (TextView) convertView.findViewById(R.id.benchmark_name);
+ name.setText(benchmark.getName());
+ CheckBox enabledBox = (CheckBox) convertView.findViewById(R.id.benchmark_enable_checkbox);
+ enabledBox.setOnClickListener(benchmark);
+ enabledBox.setChecked(benchmark.isEnabled());
+
+ return convertView;
+ }
+
+ @Override
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+
+ public int getChildrenHeight() {
+ // TODO
+ return 1024;
+ }
+}
diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/HomeActivity.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/HomeActivity.java
new file mode 100644
index 0000000000000..79bafd62e2a2c
--- /dev/null
+++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/HomeActivity.java
@@ -0,0 +1,150 @@
+/*
+ * 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.benchmark.app;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.design.widget.FloatingActionButton;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ExpandableListView;
+import android.widget.Toast;
+
+import com.android.benchmark.registry.BenchmarkRegistry;
+import com.android.benchmark.R;
+import com.android.benchmark.results.GlobalResultsStore;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.Queue;
+
+public class HomeActivity extends AppCompatActivity implements Button.OnClickListener {
+
+ private FloatingActionButton mStartButton;
+ private BenchmarkRegistry mRegistry;
+ private Queue mRunnableBenchmarks;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_home);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ mStartButton = (FloatingActionButton) findViewById(R.id.start_button);
+ mStartButton.setActivated(true);
+ mStartButton.setOnClickListener(this);
+
+ mRegistry = new BenchmarkRegistry(this);
+
+ mRunnableBenchmarks = new LinkedList<>();
+
+ ExpandableListView listView = (ExpandableListView) findViewById(R.id.test_list);
+ BenchmarkListAdapter adapter =
+ new BenchmarkListAdapter(LayoutInflater.from(this), mRegistry);
+ listView.setAdapter(adapter);
+
+ adapter.notifyDataSetChanged();
+ ViewGroup.LayoutParams layoutParams = listView.getLayoutParams();
+ layoutParams.height = 2048;
+ listView.setLayoutParams(layoutParams);
+ listView.requestLayout();
+ System.out.println(System.getProperties().stringPropertyNames());
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.menu_main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ int id = item.getItemId();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.action_settings) {
+ new AsyncTask() {
+ @Override
+ protected Void doInBackground(Void... voids) {
+ try {
+ HomeActivity.this.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(HomeActivity.this, "Exporting...", Toast.LENGTH_LONG).show();
+ }
+ });
+ GlobalResultsStore.getInstance(HomeActivity.this).exportToCsv();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ HomeActivity.this.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(HomeActivity.this, "Done", Toast.LENGTH_LONG).show();
+ }
+ });
+ }
+ }.execute();
+
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onClick(View v) {
+ final int groupCount = mRegistry.getGroupCount();
+ for (int i = 0; i < groupCount; i++) {
+
+ Intent intent = mRegistry.getBenchmarkGroup(i).getIntent();
+ if (intent != null) {
+ mRunnableBenchmarks.add(intent);
+ }
+ }
+
+ handleNextBenchmark();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+ }
+
+ private void handleNextBenchmark() {
+ Intent nextIntent = mRunnableBenchmarks.peek();
+ startActivityForResult(nextIntent, 0);
+ }
+}
diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/PerfTimeline.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/PerfTimeline.java
new file mode 100644
index 0000000000000..1c82d6db3483d
--- /dev/null
+++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/PerfTimeline.java
@@ -0,0 +1,224 @@
+/*
+ * 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.benchmark.app;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.*;
+import android.text.TextPaint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.benchmark.R;
+
+
+/**
+ * TODO: document your custom view class.
+ */
+public class PerfTimeline extends View {
+ private String mExampleString; // TODO: use a default from R.string...
+ private int mExampleColor = Color.RED; // TODO: use a default from R.color...
+ private float mExampleDimension = 300; // TODO: use a default from R.dimen...
+
+ private TextPaint mTextPaint;
+ private float mTextWidth;
+ private float mTextHeight;
+
+ private Paint mPaintBaseLow;
+ private Paint mPaintBaseHigh;
+ private Paint mPaintValue;
+
+
+ public float[] mLinesLow;
+ public float[] mLinesHigh;
+ public float[] mLinesValue;
+
+ public PerfTimeline(Context context) {
+ super(context);
+ init(null, 0);
+ }
+
+ public PerfTimeline(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ public PerfTimeline(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(attrs, defStyle);
+ }
+
+ private void init(AttributeSet attrs, int defStyle) {
+ // Load attributes
+ final TypedArray a = getContext().obtainStyledAttributes(
+ attrs, R.styleable.PerfTimeline, defStyle, 0);
+
+ mExampleString = "xx";//a.getString(R.styleable.PerfTimeline_exampleString, "xx");
+ mExampleColor = a.getColor(R.styleable.PerfTimeline_exampleColor, mExampleColor);
+ // Use getDimensionPixelSize or getDimensionPixelOffset when dealing with
+ // values that should fall on pixel boundaries.
+ mExampleDimension = a.getDimension(
+ R.styleable.PerfTimeline_exampleDimension,
+ mExampleDimension);
+
+ a.recycle();
+
+ // Set up a default TextPaint object
+ mTextPaint = new TextPaint();
+ mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+ mTextPaint.setTextAlign(Paint.Align.LEFT);
+
+ // Update TextPaint and text measurements from attributes
+ invalidateTextPaintAndMeasurements();
+
+ mPaintBaseLow = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintBaseLow.setStyle(Paint.Style.FILL);
+ mPaintBaseLow.setColor(0xff000000);
+
+ mPaintBaseHigh = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintBaseHigh.setStyle(Paint.Style.FILL);
+ mPaintBaseHigh.setColor(0x7f7f7f7f);
+
+ mPaintValue = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintValue.setStyle(Paint.Style.FILL);
+ mPaintValue.setColor(0x7fff0000);
+
+ }
+
+ private void invalidateTextPaintAndMeasurements() {
+ mTextPaint.setTextSize(mExampleDimension);
+ mTextPaint.setColor(mExampleColor);
+ mTextWidth = mTextPaint.measureText(mExampleString);
+
+ Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
+ mTextHeight = fontMetrics.bottom;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ // TODO: consider storing these as member variables to reduce
+ // allocations per draw cycle.
+ int paddingLeft = getPaddingLeft();
+ int paddingTop = getPaddingTop();
+ int paddingRight = getPaddingRight();
+ int paddingBottom = getPaddingBottom();
+
+ int contentWidth = getWidth() - paddingLeft - paddingRight;
+ int contentHeight = getHeight() - paddingTop - paddingBottom;
+
+ // Draw the text.
+ //canvas.drawText(mExampleString,
+ // paddingLeft + (contentWidth - mTextWidth) / 2,
+ // paddingTop + (contentHeight + mTextHeight) / 2,
+ // mTextPaint);
+
+
+
+
+ // Draw the shadow
+ //RectF rf = new RectF(10.f, 10.f, 100.f, 100.f);
+ //canvas.drawOval(rf, mShadowPaint);
+
+ if (mLinesLow != null) {
+ canvas.drawLines(mLinesLow, mPaintBaseLow);
+ }
+ if (mLinesHigh != null) {
+ canvas.drawLines(mLinesHigh, mPaintBaseHigh);
+ }
+ if (mLinesValue != null) {
+ canvas.drawLines(mLinesValue, mPaintValue);
+ }
+
+
+/*
+ // Draw the pie slices
+ for (int i = 0; i < mData.size(); ++i) {
+ Item it = mData.get(i);
+ mPiePaint.setShader(it.mShader);
+ canvas.drawArc(mBounds,
+ 360 - it.mEndAngle,
+ it.mEndAngle - it.mStartAngle,
+ true, mPiePaint);
+ }
+*/
+ // Draw the pointer
+ //canvas.drawLine(mTextX, mPointerY, mPointerX, mPointerY, mTextPaint);
+ //canvas.drawCircle(mPointerX, mPointerY, mPointerSize, mTextPaint);
+ }
+
+ /**
+ * Gets the example string attribute value.
+ *
+ * @return The example string attribute value.
+ */
+ public String getExampleString() {
+ return mExampleString;
+ }
+
+ /**
+ * Sets the view's example string attribute value. In the example view, this string
+ * is the text to draw.
+ *
+ * @param exampleString The example string attribute value to use.
+ */
+ public void setExampleString(String exampleString) {
+ mExampleString = exampleString;
+ invalidateTextPaintAndMeasurements();
+ }
+
+ /**
+ * Gets the example color attribute value.
+ *
+ * @return The example color attribute value.
+ */
+ public int getExampleColor() {
+ return mExampleColor;
+ }
+
+ /**
+ * Sets the view's example color attribute value. In the example view, this color
+ * is the font color.
+ *
+ * @param exampleColor The example color attribute value to use.
+ */
+ public void setExampleColor(int exampleColor) {
+ mExampleColor = exampleColor;
+ invalidateTextPaintAndMeasurements();
+ }
+
+ /**
+ * Gets the example dimension attribute value.
+ *
+ * @return The example dimension attribute value.
+ */
+ public float getExampleDimension() {
+ return mExampleDimension;
+ }
+
+ /**
+ * Sets the view's example dimension attribute value. In the example view, this dimension
+ * is the font size.
+ *
+ * @param exampleDimension The example dimension attribute value to use.
+ */
+ public void setExampleDimension(float exampleDimension) {
+ mExampleDimension = exampleDimension;
+ invalidateTextPaintAndMeasurements();
+ }
+}
diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java
new file mode 100644
index 0000000000000..7641d0095a70f
--- /dev/null
+++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/RunLocalBenchmarksActivity.java
@@ -0,0 +1,415 @@
+/*
+ * 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.benchmark.app;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.benchmark.R;
+import com.android.benchmark.registry.BenchmarkGroup;
+import com.android.benchmark.registry.BenchmarkRegistry;
+import com.android.benchmark.results.GlobalResultsStore;
+import com.android.benchmark.results.UiBenchmarkResult;
+import com.android.benchmark.synthetic.MemoryActivity;
+import com.android.benchmark.ui.BitmapUploadActivity;
+import com.android.benchmark.ui.EditTextInputActivity;
+import com.android.benchmark.ui.FullScreenOverdrawActivity;
+import com.android.benchmark.ui.ImageListViewScrollActivity;
+import com.android.benchmark.ui.ListViewScrollActivity;
+import com.android.benchmark.ui.ShadowGridActivity;
+import com.android.benchmark.ui.TextScrollActivity;
+
+import org.apache.commons.math.stat.descriptive.SummaryStatistics;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class RunLocalBenchmarksActivity extends AppCompatActivity {
+
+ public static final int RUN_COUNT = 5;
+
+ private ArrayList mBenchmarksToRun;
+ private int mBenchmarkCursor;
+ private int mCurrentRunId;
+ private boolean mFinish;
+
+ private Handler mHandler = new Handler();
+
+ private static final int[] ALL_TESTS = new int[] {
+ R.id.benchmark_list_view_scroll,
+ R.id.benchmark_image_list_view_scroll,
+ R.id.benchmark_shadow_grid,
+ R.id.benchmark_text_high_hitrate,
+ R.id.benchmark_text_low_hitrate,
+ R.id.benchmark_edit_text_input,
+ R.id.benchmark_overdraw,
+ };
+
+ public static class LocalBenchmarksList extends ListFragment {
+ private ArrayList mBenchmarks;
+ private int mRunId;
+
+ public void setBenchmarks(ArrayList benchmarks) {
+ mBenchmarks = benchmarks;
+ }
+
+ public void setRunId(int id) {
+ mRunId = id;
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ if (getActivity().findViewById(R.id.list_fragment_container) != null) {
+ FragmentManager fm = getActivity().getSupportFragmentManager();
+ UiResultsFragment resultsView = new UiResultsFragment();
+ String testName = BenchmarkRegistry.getBenchmarkName(v.getContext(),
+ mBenchmarks.get(position).id);
+ resultsView.setRunInfo(testName, mRunId);
+ FragmentTransaction fragmentTransaction = fm.beginTransaction();
+ fragmentTransaction.replace(R.id.list_fragment_container, resultsView);
+ fragmentTransaction.addToBackStack(null);
+ fragmentTransaction.commit();
+ }
+ }
+ }
+
+
+ private class LocalBenchmark {
+ int id;
+ int runCount = 0;
+ int totalCount = 0;
+ ArrayList mResultsUri = new ArrayList<>();
+
+ LocalBenchmark(int id, int runCount) {
+ this.id = id;
+ this.runCount = 0;
+ this.totalCount = runCount;
+ }
+
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_running_list);
+
+ initLocalBenchmarks(getIntent());
+
+ if (findViewById(R.id.list_fragment_container) != null) {
+ FragmentManager fm = getSupportFragmentManager();
+ LocalBenchmarksList listView = new LocalBenchmarksList();
+ listView.setListAdapter(new LocalBenchmarksListAdapter(LayoutInflater.from(this)));
+ listView.setBenchmarks(mBenchmarksToRun);
+ listView.setRunId(mCurrentRunId);
+ fm.beginTransaction().add(R.id.list_fragment_container, listView).commit();
+ }
+
+ TextView scoreView = (TextView) findViewById(R.id.score_text_view);
+ scoreView.setText("Running tests!");
+ }
+
+ private int translateBenchmarkIndex(int index) {
+ if (index >= 0 && index < ALL_TESTS.length) {
+ return ALL_TESTS[index];
+ }
+
+ return -1;
+ }
+
+ private void initLocalBenchmarks(Intent intent) {
+ mBenchmarksToRun = new ArrayList<>();
+ int[] enabledIds = intent.getIntArrayExtra(BenchmarkGroup.BENCHMARK_EXTRA_ENABLED_TESTS);
+ int runCount = intent.getIntExtra(BenchmarkGroup.BENCHMARK_EXTRA_RUN_COUNT, RUN_COUNT);
+ mFinish = intent.getBooleanExtra(BenchmarkGroup.BENCHMARK_EXTRA_FINISH, false);
+
+ if (enabledIds == null) {
+ // run all tests
+ enabledIds = ALL_TESTS;
+ }
+
+ StringBuilder idString = new StringBuilder();
+ idString.append(runCount);
+ idString.append(System.currentTimeMillis());
+
+ for (int i = 0; i < enabledIds.length; i++) {
+ int id = enabledIds[i];
+ System.out.println("considering " + id);
+ if (!isValidBenchmark(id)) {
+ System.out.println("not valid " + id);
+ id = translateBenchmarkIndex(id);
+ System.out.println("got out " + id);
+ System.out.println("expected: " + R.id.benchmark_overdraw);
+ }
+
+ if (isValidBenchmark(id)) {
+ int localRunCount = runCount;
+ if (isCompute(id)) {
+ localRunCount = 1;
+ }
+ mBenchmarksToRun.add(new LocalBenchmark(id, localRunCount));
+ idString.append(id);
+ }
+ }
+
+ mBenchmarkCursor = 0;
+ mCurrentRunId = idString.toString().hashCode();
+ }
+
+ private boolean isCompute(int id) {
+ switch (id) {
+ case R.id.benchmark_cpu_gflops:
+ case R.id.benchmark_cpu_heat_soak:
+ case R.id.benchmark_memory_bandwidth:
+ case R.id.benchmark_memory_latency:
+ case R.id.benchmark_power_management:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isValidBenchmark(int benchmarkId) {
+ switch (benchmarkId) {
+ case R.id.benchmark_list_view_scroll:
+ case R.id.benchmark_image_list_view_scroll:
+ case R.id.benchmark_shadow_grid:
+ case R.id.benchmark_text_high_hitrate:
+ case R.id.benchmark_text_low_hitrate:
+ case R.id.benchmark_edit_text_input:
+ case R.id.benchmark_overdraw:
+ case R.id.benchmark_memory_bandwidth:
+ case R.id.benchmark_memory_latency:
+ case R.id.benchmark_power_management:
+ case R.id.benchmark_cpu_heat_soak:
+ case R.id.benchmark_cpu_gflops:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ runNextBenchmark();
+ }
+ }, 1000);
+ }
+
+ private void computeOverallScore() {
+ final TextView scoreView = (TextView) findViewById(R.id.score_text_view);
+ scoreView.setText("Computing score...");
+ new AsyncTask() {
+ @Override
+ protected Integer doInBackground(Void... voids) {
+ GlobalResultsStore gsr =
+ GlobalResultsStore.getInstance(RunLocalBenchmarksActivity.this);
+ ArrayList testLevelScores = new ArrayList<>();
+ final SummaryStatistics stats = new SummaryStatistics();
+ for (LocalBenchmark b : mBenchmarksToRun) {
+ HashMap> detailedResults =
+ gsr.loadDetailedResults(mCurrentRunId);
+ for (ArrayList testResult : detailedResults.values()) {
+ for (UiBenchmarkResult res : testResult) {
+ int score = res.getScore();
+ if (score == 0) {
+ score = 1;
+ }
+ stats.addValue(score);
+ }
+
+ testLevelScores.add(stats.getGeometricMean());
+ stats.clear();
+ }
+
+ }
+
+ for (double score : testLevelScores) {
+ stats.addValue(score);
+ }
+
+ return (int)Math.round(stats.getGeometricMean());
+ }
+
+ @Override
+ protected void onPostExecute(Integer score) {
+ TextView view = (TextView)
+ RunLocalBenchmarksActivity.this.findViewById(R.id.score_text_view);
+ view.setText("Score: " + score);
+ }
+ }.execute();
+ }
+
+ private void runNextBenchmark() {
+ LocalBenchmark benchmark = mBenchmarksToRun.get(mBenchmarkCursor);
+ boolean runAgain = false;
+
+ if (benchmark.runCount < benchmark.totalCount) {
+ runBenchmarkForId(mBenchmarksToRun.get(mBenchmarkCursor).id, benchmark.runCount++);
+ } else if (mBenchmarkCursor + 1 < mBenchmarksToRun.size()) {
+ mBenchmarkCursor++;
+ benchmark = mBenchmarksToRun.get(mBenchmarkCursor);
+ runBenchmarkForId(benchmark.id, benchmark.runCount++);
+ } else if (runAgain) {
+ mBenchmarkCursor = 0;
+ initLocalBenchmarks(getIntent());
+
+ runBenchmarkForId(mBenchmarksToRun.get(mBenchmarkCursor).id, benchmark.runCount);
+ } else if (mFinish) {
+ finish();
+ } else {
+ Log.i("BENCH", "BenchmarkDone!");
+ computeOverallScore();
+ }
+ }
+
+ private void runBenchmarkForId(int id, int iteration) {
+ Intent intent;
+ int syntheticTestId = -1;
+
+ System.out.println("iteration: " + iteration);
+
+ switch (id) {
+ case R.id.benchmark_list_view_scroll:
+ intent = new Intent(getApplicationContext(), ListViewScrollActivity.class);
+ break;
+ case R.id.benchmark_image_list_view_scroll:
+ intent = new Intent(getApplicationContext(), ImageListViewScrollActivity.class);
+ break;
+ case R.id.benchmark_shadow_grid:
+ intent = new Intent(getApplicationContext(), ShadowGridActivity.class);
+ break;
+ case R.id.benchmark_text_high_hitrate:
+ intent = new Intent(getApplicationContext(), TextScrollActivity.class);
+ intent.putExtra(TextScrollActivity.EXTRA_HIT_RATE, 80);
+ intent.putExtra(BenchmarkRegistry.EXTRA_ID, id);
+ break;
+ case R.id.benchmark_text_low_hitrate:
+ intent = new Intent(getApplicationContext(), TextScrollActivity.class);
+ intent.putExtra(TextScrollActivity.EXTRA_HIT_RATE, 20);
+ intent.putExtra(BenchmarkRegistry.EXTRA_ID, id);
+ break;
+ case R.id.benchmark_edit_text_input:
+ intent = new Intent(getApplicationContext(), EditTextInputActivity.class);
+ break;
+ case R.id.benchmark_overdraw:
+ intent = new Intent(getApplicationContext(), BitmapUploadActivity.class);
+ break;
+ case R.id.benchmark_memory_bandwidth:
+ syntheticTestId = 0;
+ intent = new Intent(getApplicationContext(), MemoryActivity.class);
+ intent.putExtra("test", syntheticTestId);
+ break;
+ case R.id.benchmark_memory_latency:
+ syntheticTestId = 1;
+ intent = new Intent(getApplicationContext(), MemoryActivity.class);
+ intent.putExtra("test", syntheticTestId);
+ break;
+ case R.id.benchmark_power_management:
+ syntheticTestId = 2;
+ intent = new Intent(getApplicationContext(), MemoryActivity.class);
+ intent.putExtra("test", syntheticTestId);
+ break;
+ case R.id.benchmark_cpu_heat_soak:
+ syntheticTestId = 3;
+ intent = new Intent(getApplicationContext(), MemoryActivity.class);
+ intent.putExtra("test", syntheticTestId);
+ break;
+ case R.id.benchmark_cpu_gflops:
+ syntheticTestId = 4;
+ intent = new Intent(getApplicationContext(), MemoryActivity.class);
+ intent.putExtra("test", syntheticTestId);
+ break;
+
+ default:
+ intent = null;
+ }
+
+ if (intent != null) {
+ intent.putExtra("com.android.benchmark.RUN_ID", mCurrentRunId);
+ intent.putExtra("com.android.benchmark.ITERATION", iteration);
+ startActivityForResult(intent, id & 0xffff, null);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case R.id.benchmark_shadow_grid:
+ case R.id.benchmark_list_view_scroll:
+ case R.id.benchmark_image_list_view_scroll:
+ case R.id.benchmark_text_high_hitrate:
+ case R.id.benchmark_text_low_hitrate:
+ case R.id.benchmark_edit_text_input:
+ break;
+ default:
+ }
+ }
+
+ class LocalBenchmarksListAdapter extends BaseAdapter {
+
+ private final LayoutInflater mInflater;
+
+ LocalBenchmarksListAdapter(LayoutInflater inflater) {
+ mInflater = inflater;
+ }
+
+ @Override
+ public int getCount() {
+ return mBenchmarksToRun.size();
+ }
+
+ @Override
+ public Object getItem(int i) {
+ return mBenchmarksToRun.get(i);
+ }
+
+ @Override
+ public long getItemId(int i) {
+ return mBenchmarksToRun.get(i).id;
+ }
+
+ @Override
+ public View getView(int i, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.running_benchmark_list_item, null);
+ }
+
+ TextView name = (TextView) convertView.findViewById(R.id.benchmark_name);
+ name.setText(BenchmarkRegistry.getBenchmarkName(
+ RunLocalBenchmarksActivity.this, mBenchmarksToRun.get(i).id));
+ return convertView;
+ }
+
+ }
+}
diff --git a/tests/JankBench/app/src/main/java/com/android/benchmark/app/UiResultsFragment.java b/tests/JankBench/app/src/main/java/com/android/benchmark/app/UiResultsFragment.java
new file mode 100644
index 0000000000000..56e94d538ab5f
--- /dev/null
+++ b/tests/JankBench/app/src/main/java/com/android/benchmark/app/UiResultsFragment.java
@@ -0,0 +1,167 @@
+/*
+ * 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.benchmark.app;
+
+import android.annotation.TargetApi;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.ListFragment;
+import android.util.Log;
+import android.view.FrameMetrics;
+import android.widget.SimpleAdapter;
+
+import com.android.benchmark.R;
+import com.android.benchmark.registry.BenchmarkGroup;
+import com.android.benchmark.registry.BenchmarkRegistry;
+import com.android.benchmark.results.GlobalResultsStore;
+import com.android.benchmark.results.UiBenchmarkResult;
+
+import org.apache.commons.math.stat.descriptive.SummaryStatistics;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URI;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+@TargetApi(24)
+public class UiResultsFragment extends ListFragment {
+ private static final String TAG = "UiResultsFragment";
+ private static final int NUM_FIELDS = 20;
+
+ private ArrayList mResults = new ArrayList<>();
+
+ private AsyncTask>> mLoadScoresTask =
+ new AsyncTask>>() {
+ @Override
+ protected ArrayList