From 794b6b35ce4898cd3d4e3eea1d28ea4e69dfb575 Mon Sep 17 00:00:00 2001 From: Robert Spencer Date: Wed, 15 Mar 2017 09:08:55 -0700 Subject: [PATCH] YogaLayout perf tests Summary: We would like to know some numbers on benchmarking `YogaLayout` against other layouts, particularly `LinearLayout`. This implements a `BenchmarkActivity` to fill that need. Reviewed By: emilsjolander Differential Revision: D4565531 fbshipit-source-id: fe1c558beb603c3116ac3d0dd6654b0376dd6b8a --- android/sample/AndroidManifest.xml | 7 + .../samples/yoga/BenchmarkActivity.java | 113 ++++++++++ .../samples/yoga/BenchmarkAggregator.java | 193 ++++++++++++++++ .../samples/yoga/BenchmarkFragment.java | 110 ++++++++++ .../samples/yoga/BenchmarkInflate.java | 65 ++++++ .../samples/yoga/BenchmarkLayout.java | 74 +++++++ .../samples/yoga/BenchmarkMeasure.java | 75 +++++++ .../facebook/samples/yoga/MainActivity.java | 20 ++ .../sample/res/layout/benchmark_fragment.xml | 50 +++++ .../sample/res/layout/benchmark_layout_1.xml | 30 +++ .../res/layout/benchmark_layout_1_linear.xml | 28 +++ .../sample/res/layout/benchmark_layout_2.xml | 104 +++++++++ .../res/layout/benchmark_layout_2_linear.xml | 96 ++++++++ .../sample/res/layout/benchmark_layout_3.xml | 206 ++++++++++++++++++ .../res/layout/benchmark_layout_3_linear.xml | 204 +++++++++++++++++ .../res/layout/benchmark_select_layout.xml | 7 + .../sample/res/menu/action_bar_benchmark.xml | 19 ++ android/sample/res/menu/action_bar_home.xml | 19 ++ .../com/facebook/yoga/android/YogaLayout.java | 3 +- lib/soloader/soloader-0.1.0.aar | Bin 41685 -> 41801 bytes 20 files changed, 1422 insertions(+), 1 deletion(-) create mode 100644 android/sample/java/com/facebook/samples/yoga/BenchmarkActivity.java create mode 100644 android/sample/java/com/facebook/samples/yoga/BenchmarkAggregator.java create mode 100644 android/sample/java/com/facebook/samples/yoga/BenchmarkFragment.java create mode 100644 android/sample/java/com/facebook/samples/yoga/BenchmarkInflate.java create mode 100644 android/sample/java/com/facebook/samples/yoga/BenchmarkLayout.java create mode 100644 android/sample/java/com/facebook/samples/yoga/BenchmarkMeasure.java create mode 100644 android/sample/res/layout/benchmark_fragment.xml create mode 100644 android/sample/res/layout/benchmark_layout_1.xml create mode 100644 android/sample/res/layout/benchmark_layout_1_linear.xml create mode 100644 android/sample/res/layout/benchmark_layout_2.xml create mode 100644 android/sample/res/layout/benchmark_layout_2_linear.xml create mode 100644 android/sample/res/layout/benchmark_layout_3.xml create mode 100644 android/sample/res/layout/benchmark_layout_3_linear.xml create mode 100644 android/sample/res/layout/benchmark_select_layout.xml create mode 100644 android/sample/res/menu/action_bar_benchmark.xml create mode 100644 android/sample/res/menu/action_bar_home.xml diff --git a/android/sample/AndroidManifest.xml b/android/sample/AndroidManifest.xml index e5da6654..a47e1e0d 100644 --- a/android/sample/AndroidManifest.xml +++ b/android/sample/AndroidManifest.xml @@ -22,6 +22,8 @@ android:targetSdkVersion="19" /> + + + + diff --git a/android/sample/java/com/facebook/samples/yoga/BenchmarkActivity.java b/android/sample/java/com/facebook/samples/yoga/BenchmarkActivity.java new file mode 100644 index 00000000..fa1fb54b --- /dev/null +++ b/android/sample/java/com/facebook/samples/yoga/BenchmarkActivity.java @@ -0,0 +1,113 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.samples.yoga; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.ViewPager; +import android.view.LayoutInflater; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.Menu; +import android.support.v7.app.ActionBar; + +import com.facebook.samples.yoga.R; +import com.facebook.yoga.android.YogaViewLayoutFactory; + +public class BenchmarkActivity extends ActionBarActivity { + + @Override + public void onCreate(Bundle savedInstanceState) { + LayoutInflater.from(this).setFactory(YogaViewLayoutFactory.getInstance()); + super.onCreate(savedInstanceState); + + setContentView(R.layout.benchmark_select_layout); + + ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); + viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager())); + + final ActionBar actionBar = getSupportActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + + ActionBar.TabListener tabListener = new ActionBar.TabListener() { + public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { + ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager); + viewPager.setCurrentItem(tab.getPosition()); + } + + public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { + } + + public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { + } + }; + actionBar.addTab( + actionBar.newTab() + .setText("Inflate") + .setTabListener(tabListener)); + actionBar.addTab( + actionBar.newTab() + .setText("Measure") + .setTabListener(tabListener)); + actionBar.addTab( + actionBar.newTab() + .setText("Layout") + .setTabListener(tabListener)); + + viewPager.setOnPageChangeListener( + new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + // When swiping between pages, select the + // corresponding tab. + actionBar.setSelectedNavigationItem(position); + } + }); + + viewPager.setOffscreenPageLimit(3); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.action_bar_benchmark, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // There is only one option + Intent intent = new Intent(this, MainActivity.class); + startActivity(intent); + this.finish(); + return true; + } + + public static class PagerAdapter extends FragmentPagerAdapter { + public PagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int i) { + switch (i) { + case 0: + return new BenchmarkInflate(); + case 1: + return new BenchmarkMeasure(); + default: + return new BenchmarkLayout(); + } + } + + @Override + public int getCount() { + return 3; + } + } +} diff --git a/android/sample/java/com/facebook/samples/yoga/BenchmarkAggregator.java b/android/sample/java/com/facebook/samples/yoga/BenchmarkAggregator.java new file mode 100644 index 00000000..2fc57896 --- /dev/null +++ b/android/sample/java/com/facebook/samples/yoga/BenchmarkAggregator.java @@ -0,0 +1,193 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.samples.yoga; + +import java.io.File; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.lang.Math; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.text.DateFormat; +import java.util.Date; + +import android.content.Context; +import android.util.Log; +import android.os.Environment; + +import static java.util.Collections.sort; + +public class BenchmarkAggregator { + + private final int GRAPH_WIDTH = 30; + private final int GRAPH_HEIGHT = 6; + + private List times; + private boolean tracing; + private long lastTraceStart; + + private boolean statsFresh; + private long mean; + private long variance; + private long stddev; + private long min; + private long max; + private long p10; + private long p50; + private long p90; + + private String name; + + public BenchmarkAggregator(String name) { + times = new ArrayList<>(); + tracing = false; + this.name = name; + } + + public void startTrace() { + if (tracing) { + throw new RuntimeException("Cannot start trace while running previous one"); + } + tracing = true; + lastTraceStart = System.nanoTime(); + } + + public void endTrace() { + if (!tracing) { + throw new RuntimeException("Cannot stop trace if none are running!"); + } + times.add(System.nanoTime() - lastTraceStart); + tracing = false; + statsFresh = false; + } + + private void computeStats() { + if (statsFresh) { + return; + } + + sort(times); + + min = Long.MAX_VALUE; + max = -1; + mean = 0; + for (long f: times) { + mean += f; + if (f < min) { + min = f; + } + if (f > max) { + max = f; + } + } + mean /= times.size(); + + variance = 0; + for (long f: times) { + variance += (f-mean)*(f-mean); + } + variance /= times.size(); + stddev = (long) Math.sqrt((double) variance); + + p10 = times.get(times.size()*10/100); + p50 = times.get(times.size()*50/100); + p90 = times.get(times.size()*90/100); + + statsFresh = true; + } + + public String toString() { + computeStats(); + return String.format( + "%s:\n" + + "| %d samples\n" + + "| Mean %.3f\u00B1%.3fms\n" + // plusminus + "| Min %.3fms ; Max %.3fms\n" + + "| p10 %.3fms ; p50 %.3fms ; p90 %.3fms\n" + + "%s", + name, + times.size(), + mean/10e6, + stddev/10e6, + min/10e6, + max/10e6, + p10/10e6, + p50/10e6, + p90/10e6, + makeGraph()); + } + + private String makeGraph() { + char canvas[][] = new char[GRAPH_HEIGHT][GRAPH_WIDTH]; + for (int i = 0; i < GRAPH_HEIGHT; i++) + for (int j = 0; j < GRAPH_WIDTH; j++) + canvas[i][j] = ' '; + + long bucketSize = (p90 - p10) / GRAPH_WIDTH+1; + int bucketCount[] = new int[GRAPH_WIDTH]; + for (long time : times) { + if (timep10) { + bucketCount[(int) ((time - p10) / bucketSize)]++; + } + } + + int maxBucket = 0; + for (int i = 0; i < GRAPH_WIDTH; i++) + if (bucketCount[i] > maxBucket) { + maxBucket = bucketCount[i]; + } + + for (int i = 0; i < GRAPH_HEIGHT; i++) + for (int j = 0; j < GRAPH_WIDTH; j++) + if (i < bucketCount[j] * GRAPH_HEIGHT / maxBucket) { + canvas[i][j] = 'Z'; + } + + String graph = new String(); + for (int i = 0; i < GRAPH_HEIGHT; i++) + { + int percentage = 100 * (GRAPH_HEIGHT - i - 1) * maxBucket / (times.size() * GRAPH_HEIGHT); + graph += String.format("| %2d%% ", percentage); + for (int j = 0; j < GRAPH_WIDTH; j++) + graph += canvas[GRAPH_HEIGHT-1-i][j]; + graph += '\n'; + } + + graph += "| p10"; + for (int i = 0; i < GRAPH_WIDTH-6; i++) + graph += " "; + graph += "p90\n"; + return graph; + } + + /** + * Dumps the collected times to a file on the device. This allows us to grab the raw data + * and perform more in-depth analysis. + */ + public void dump(Context context) { + String state = Environment.getExternalStorageState(); + if (!Environment.MEDIA_MOUNTED.equals(state)) { + Log.e("YogaLayoutBenchmark","No external file storage"); + return; + } + + SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); + String filename = format.format(new Date()) + "_" + name.replace(' ','_'); + File file = new File(context.getExternalFilesDir( + Environment.DIRECTORY_DOCUMENTS), filename); + + try { + PrintWriter printWriter = new PrintWriter(file); + for (long l : times) { + printWriter.println(l); + } + printWriter.close(); + + Log.i("YogaLayoutBenchmark","Benchmark data saved in "+file.getPath()); + } catch (java.io.IOException e) { + Log.e("YogaLayoutBenchmark", "Could not save benchmark data", e); + } + } +} diff --git a/android/sample/java/com/facebook/samples/yoga/BenchmarkFragment.java b/android/sample/java/com/facebook/samples/yoga/BenchmarkFragment.java new file mode 100644 index 00000000..bc692290 --- /dev/null +++ b/android/sample/java/com/facebook/samples/yoga/BenchmarkFragment.java @@ -0,0 +1,110 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.samples.yoga; + + +import java.util.Random; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.LinearLayout; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.ArrayAdapter; +import android.widget.AdapterView; + +import com.facebook.samples.yoga.R; +import com.facebook.yoga.android.YogaLayout; + +public class BenchmarkFragment extends Fragment implements AdapterView.OnItemSelectedListener { + private LayoutInflater mInflater; + + protected com.facebook.yoga.android.YogaLayout rootLayout; + protected int yogaLayout; + protected int linearLayout; + + static final Random random = new Random(); + + static void randomizeText(View root) { + if (root instanceof TextView) { + ((TextView) root).setText("" + random.nextInt(1000)); + ((TextView) root).setTextSize(10 + random.nextInt(20)); + ViewParent parent = root.getParent(); + if (parent instanceof YogaLayout) { + ((YogaLayout) parent).invalidate(root); + } + } else if (root instanceof ViewGroup) { + for (int i = 0; i < ((ViewGroup) root).getChildCount(); i++) { + randomizeText(((ViewGroup) root).getChildAt(i)); + } + } + } + + public BenchmarkFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView( + LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + mInflater = inflater; + + rootLayout = (YogaLayout) inflater.inflate( + R.layout.benchmark_fragment, + container, + false); + + Spinner benchmarkSelect = (Spinner) rootLayout.findViewById(R.id.benchmarkSelect); + String[] items = new String[]{"Basic", "Typical", "Nested"}; + ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_dropdown_item, items); + benchmarkSelect.setAdapter(adapter); + benchmarkSelect.setOnItemSelectedListener(this); + return rootLayout; + } + + @Override + public void onItemSelected(AdapterView parent, View view, int pos, long id) { + switch (pos) { + case 0: + yogaLayout = R.layout.benchmark_layout_1; + linearLayout = R.layout.benchmark_layout_1_linear; + break; + case 1: + yogaLayout = R.layout.benchmark_layout_2; + linearLayout = R.layout.benchmark_layout_2_linear; + break; + case 2: + default: + yogaLayout = R.layout.benchmark_layout_3; + linearLayout = R.layout.benchmark_layout_3_linear; + break; + } + updatePreview(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + yogaLayout = R.layout.benchmark_layout_1; + linearLayout = R.layout.benchmark_layout_1_linear; + updatePreview(); + } + + private void updatePreview() { + LinearLayout previewLayout = (LinearLayout) rootLayout.findViewById(R.id.preview); + View v = mInflater.inflate(yogaLayout, rootLayout, false); + v.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT)); + previewLayout.removeAllViews(); + previewLayout.addView(v); + } +} diff --git a/android/sample/java/com/facebook/samples/yoga/BenchmarkInflate.java b/android/sample/java/com/facebook/samples/yoga/BenchmarkInflate.java new file mode 100644 index 00000000..b3a24474 --- /dev/null +++ b/android/sample/java/com/facebook/samples/yoga/BenchmarkInflate.java @@ -0,0 +1,65 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.samples.yoga; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; +import android.widget.Button; +import android.view.ViewGroup; +import android.util.Log; +import com.facebook.samples.yoga.R; + +public class BenchmarkInflate extends BenchmarkFragment { + + @Override + public View onCreateView( + LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + + Button b = (Button) rootLayout.findViewById(R.id.btn); + b.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startBenchmark(); + } + }); + + return rootLayout; + } + + protected void startBenchmark() { + LayoutInflater inflater = LayoutInflater.from(getActivity()); + TextView textView = (TextView) rootLayout.findViewById(R.id.text); + + final int ITERATIONS = 500; + + inflater.inflate(yogaLayout, null); + inflater.inflate(linearLayout, null); + + BenchmarkAggregator yogaInflationAggregator = new BenchmarkAggregator("Yoga Inflate"); + BenchmarkAggregator linearInflationAggregator = new BenchmarkAggregator("Linear Inflate"); + for (int i = 0; i < ITERATIONS; i++) { + yogaInflationAggregator.startTrace(); + inflater.inflate(yogaLayout, null); + yogaInflationAggregator.endTrace(); + linearInflationAggregator.startTrace(); + inflater.inflate(linearLayout, null); + linearInflationAggregator.endTrace(); + } + + textView.setText( + yogaInflationAggregator.toString()+ + "\n"+ + linearInflationAggregator.toString()); + Log.i( + "YogaLayoutBenchmark", + yogaInflationAggregator.toString()+ + "\n"+ + linearInflationAggregator.toString()); + rootLayout.invalidate(); + } +} diff --git a/android/sample/java/com/facebook/samples/yoga/BenchmarkLayout.java b/android/sample/java/com/facebook/samples/yoga/BenchmarkLayout.java new file mode 100644 index 00000000..8fdcdb64 --- /dev/null +++ b/android/sample/java/com/facebook/samples/yoga/BenchmarkLayout.java @@ -0,0 +1,74 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.samples.yoga; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import com.facebook.samples.yoga.R; + +import java.util.Random; + +public class BenchmarkLayout extends BenchmarkFragment { + + @Override + public View onCreateView( + LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + + Button b = (Button) rootLayout.findViewById(R.id.btn); + b.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startBenchmark(); + } + }); + + return rootLayout; + } + + protected void startBenchmark() { + LayoutInflater inflater = LayoutInflater.from(getActivity()); + TextView textView = (TextView) rootLayout.findViewById(R.id.text); + Random random = new Random(); + + final int ITERATIONS = 500; + + BenchmarkAggregator yogaInflationAggregator = new BenchmarkAggregator("Yoga Layout"); + BenchmarkAggregator linearInflationAggregator = new BenchmarkAggregator("Linear Layout"); + View yogaView = inflater.inflate(yogaLayout, null); + View linearView = inflater.inflate(linearLayout, null); + for (int i = 0; i < ITERATIONS; i++) { + randomizeText(yogaView); + randomizeText(linearView); + yogaView.measure( + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); + linearView.measure( + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); + yogaInflationAggregator.startTrace(); + yogaView.layout(0, 0, yogaView.getMeasuredWidth(), yogaView.getMeasuredHeight()); + yogaInflationAggregator.endTrace(); + linearInflationAggregator.startTrace(); + linearView.layout(0, 0, linearView.getMeasuredWidth(), linearView.getMeasuredHeight()); + linearInflationAggregator.endTrace(); + } + + textView.setText( + yogaInflationAggregator.toString()+ + "\n"+ + linearInflationAggregator.toString()); + Log.i( + "YogaLayoutBenchmark", + yogaInflationAggregator.toString()+ + "\n"+ + linearInflationAggregator.toString()); + } +} diff --git a/android/sample/java/com/facebook/samples/yoga/BenchmarkMeasure.java b/android/sample/java/com/facebook/samples/yoga/BenchmarkMeasure.java new file mode 100644 index 00000000..51151878 --- /dev/null +++ b/android/sample/java/com/facebook/samples/yoga/BenchmarkMeasure.java @@ -0,0 +1,75 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.samples.yoga; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; +import com.facebook.samples.yoga.R; + +import java.util.Random; + +public class BenchmarkMeasure extends BenchmarkFragment { + + @Override + public View onCreateView( + LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + + Button b = (Button) rootLayout.findViewById(R.id.btn); + b.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startBenchmark(); + } + }); + + return rootLayout; + } + + protected void startBenchmark() { + LayoutInflater inflater = LayoutInflater.from(getActivity()); + TextView textView = (TextView) rootLayout.findViewById(R.id.text); + Random random = new Random(); + + final int ITERATIONS = 500; + + BenchmarkAggregator yogaMeasureAggregator = new BenchmarkAggregator("Yoga Measure"); + BenchmarkAggregator linearMeasureAggregator = new BenchmarkAggregator("Linear Measure"); + View yogaView = inflater.inflate(yogaLayout, null); + View linearView = inflater.inflate(linearLayout, null); + for (int i = 0; i < ITERATIONS; i++) { + randomizeText(yogaView); + randomizeText(linearView); + yogaMeasureAggregator.startTrace(); + yogaView.measure( + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); + yogaMeasureAggregator.endTrace(); + linearMeasureAggregator.startTrace(); + linearView.measure( + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)); + linearMeasureAggregator.endTrace(); + } + + textView.setText( + yogaMeasureAggregator.toString()+ + "\n"+ + linearMeasureAggregator.toString()); + Log.i( + "YogaLayoutBenchmark", + yogaMeasureAggregator.toString()+ + "\n"+ + linearMeasureAggregator.toString()); + + yogaMeasureAggregator.dump(getActivity()); + linearMeasureAggregator.dump(getActivity()); + } +} diff --git a/android/sample/java/com/facebook/samples/yoga/MainActivity.java b/android/sample/java/com/facebook/samples/yoga/MainActivity.java index 52649a1a..fbc45b99 100644 --- a/android/sample/java/com/facebook/samples/yoga/MainActivity.java +++ b/android/sample/java/com/facebook/samples/yoga/MainActivity.java @@ -8,9 +8,13 @@ package com.facebook.samples.yoga; +import android.content.Intent; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.Menu; import com.facebook.samples.yoga.R; import com.facebook.soloader.SoLoader; @@ -31,4 +35,20 @@ public class MainActivity extends ActionBarActivity { setContentView(R.layout.main_layout); } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.action_bar_home, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // There is only one option + Intent intent = new Intent(this, BenchmarkActivity.class); + startActivity(intent); + this.finish(); + return true; + } } diff --git a/android/sample/res/layout/benchmark_fragment.xml b/android/sample/res/layout/benchmark_fragment.xml new file mode 100644 index 00000000..6f9bdbd9 --- /dev/null +++ b/android/sample/res/layout/benchmark_fragment.xml @@ -0,0 +1,50 @@ + + + +