Android: Implement a better benchmark editor that knows about the scenes and their options.
diff --git a/android/res/layout/activity_editor.xml b/android/res/layout/activity_editor.xml
index e04f742..c08acda 100644
--- a/android/res/layout/activity_editor.xml
+++ b/android/res/layout/activity_editor.xml
@@ -3,16 +3,20 @@
android:layout_width="match_parent"
android:layout_height="match_parent" >
- <EditText android:id="@+id/benchmarkEditorTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:gravity="top"
- android:inputType="textMultiLine"
- android:minLines="3">
- <requestFocus/>
- </EditText>
+ <Button android:id="@+id/saveButton"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:text="Save" />
+ <ListView android:id="@+id/editorListView"
+ android:layout_above="@id/saveButton"
+ android:layout_weight="1.0"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip" />
</RelativeLayout>
diff --git a/android/res/layout/benchmark_item.xml b/android/res/layout/benchmark_item.xml
index 632bc5e..5a70988 100644
--- a/android/res/layout/benchmark_item.xml
+++ b/android/res/layout/benchmark_item.xml
@@ -11,9 +11,6 @@
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView android:id="@+id/summary"
@@ -21,7 +18,6 @@
android:layout_height="wrap_content"
android:layout_alignLeft="@id/title"
android:layout_below="@id/title"
- android:maxLines="4"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
diff --git a/android/src/org/linaro/glmark2/EditorActivity.java b/android/src/org/linaro/glmark2/EditorActivity.java
index ddf874b..c7ee64d 100644
--- a/android/src/org/linaro/glmark2/EditorActivity.java
+++ b/android/src/org/linaro/glmark2/EditorActivity.java
@@ -1,48 +1,442 @@
+/*
+ * Copyright © 2012 Linaro Limited
+ *
+ * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
+ *
+ * glmark2 is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * glmark2. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexandros Frantzis
+ */
package org.linaro.glmark2;
-import android.os.Bundle;
+import java.util.ArrayList;
+
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.SpannableString;
+import android.text.style.ForegroundColorSpan;
import android.util.Log;
-import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemLongClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
-import android.content.Intent;
-import android.view.WindowManager;
public class EditorActivity extends Activity {
+ public static final int DIALOG_SCENE_NAME_ID = 0;
+ public static final int DIALOG_SCENE_OPTION_ID = 1;
+
+ private EditorItemAdapter adapter;
+ private ArrayList<SceneInfo> sceneInfoList;
+ private String[] sceneNames;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
- /* Show the soft-keyboard */
- getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ /* Get information about the available scenes */
+ sceneInfoList = getSceneInfoList();
+ sceneNames = getSceneNames();
- /* Get the benchmark position as sent by the main activity */
+ /* Read information sent by the main activity */
final int benchmarkPos = this.getIntent().getIntExtra("benchmark-pos", 0);
+ String benchmarkText = getIntent().getStringExtra("benchmark-text");
+ if (benchmarkText.isEmpty())
+ benchmarkText = sceneNames[0];
- /* Set the textview widget text */
- TextView tv = (TextView) findViewById(R.id.benchmarkEditorTextView);
- tv.setText(getIntent().getStringExtra("benchmark-text"));
+ /* Set up the save button */
+ Button button = (Button) findViewById(R.id.saveButton);
+ button.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ String newBenchmarkText = getBenchmarkDescriptionText();
+ Intent intent = new Intent();
+ intent.putExtra("benchmark-text", newBenchmarkText);
+ intent.putExtra("benchmark-pos", benchmarkPos);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+ });
- /* Handle editor events */
- tv.setOnEditorActionListener(new OnEditorActionListener() {
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_DONE ||
- (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER &&
- event.getAction() == KeyEvent.ACTION_UP))
- {
- /* Return result to caller activity */
- Intent intent = new Intent();
- intent.putExtra("benchmark-text", v.getText().toString());
- intent.putExtra("benchmark-pos", benchmarkPos);
- setResult(RESULT_OK, intent);
- finish();
+ /* Set up list view */
+ ListView lv = (ListView) findViewById(R.id.editorListView);
+ adapter = new EditorItemAdapter(this, R.layout.benchmark_item,
+ getEditorItemList(benchmarkText));
+ lv.setAdapter(adapter);
+
+ lv.setOnItemClickListener(new OnItemClickListener() {
+ public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
+ Bundle bundle = new Bundle();
+ bundle.putInt("item-pos", position);
+ /* Show the right dialog, depending on the clicked list position */
+ if (position == 0)
+ showDialog(DIALOG_SCENE_NAME_ID, bundle);
+ else
+ showDialog(DIALOG_SCENE_OPTION_ID, bundle);
+ }
+ });
+
+ lv.setOnItemLongClickListener(new OnItemLongClickListener() {
+ public boolean onItemLongClick(AdapterView<?> parentView, View childView, int position, long id) {
+ /* Reset the value of the long-clicked option */
+ if (position > 0) {
+ EditorItem item = adapter.getItem(position);
+ item.value = null;
+ adapter.notifyDataSetChanged();
}
return true;
}
});
}
+
+ @Override
+ protected Dialog onCreateDialog(int id, Bundle bundle) {
+ final int itemPos = bundle.getInt("item-pos");
+ Dialog dialog;
+
+ switch (id) {
+ case DIALOG_SCENE_NAME_ID:
+ {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Pick a scene");
+ builder.setItems(sceneNames, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ adapter.clear();
+ for (EditorItem ei: getEditorItemList(sceneNames[item]))
+ adapter.add(ei);
+ adapter.notifyDataSetChanged();
+ removeDialog(DIALOG_SCENE_NAME_ID);
+ }
+ });
+ dialog = builder.create();
+ }
+ break;
+
+ case DIALOG_SCENE_OPTION_ID:
+ {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ final EditorItem item = adapter.getItem(itemPos);
+ final EditText input = new EditText(this);
+ if (item.value != null)
+ input.setText(item.value);
+
+ input.setOnEditorActionListener(new OnEditorActionListener() {
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == EditorInfo.IME_ACTION_DONE ||
+ (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER &&
+ event.getAction() == KeyEvent.ACTION_UP))
+ {
+ item.value = v.getText().toString();
+ removeDialog(DIALOG_SCENE_OPTION_ID);
+ }
+ return true;
+ }
+ });
+ builder.setTitle(item.option.name + ": " + item.option.description);
+ dialog = builder.create();
+ ((AlertDialog)dialog).setView(input, 15, 6, 15, 6);
+ }
+ break;
+
+ default:
+ dialog = null;
+ break;
+ }
+
+ return dialog;
+ }
+
+ /**
+ * Gets the value of an option.
+ *
+ * @param benchArray an array of option strings ("opt=val")
+ * @param opt the options to get the value of
+ *
+ * @return the value or null
+ */
+ private String getOptionValue(String[] benchArray, String opt) {
+ String ret = null;
+
+ /* Search from the end to the beginning */
+ for (int n = benchArray.length - 1; n >= 0; n--) {
+ String s = benchArray[n].trim();
+ if (s.startsWith(opt + "=")) {
+ int i = s.indexOf('=');
+ if (i >= 0 && i + 1 < s.length()) {
+ ret = s.substring(i + 1).trim();
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Gets the benchmark description string of the current editing state.
+ *
+ * @return the string
+ */
+ private String getBenchmarkDescriptionText() {
+ String ret = "";
+
+ for (int i = 0; i < adapter.getCount(); i++) {
+ /* Convert each list item to a proper string representation */
+ EditorItem item = adapter.getItem(i);
+ String s = "";
+
+ /*
+ * Append "opt=" if this is an option item, except the
+ * "__custom__" item.
+ */
+ if (item.option != null && item.value != null &&
+ !item.option.name.equals("__custom__"))
+ {
+ s += item.option.name + "=";
+ }
+
+ /*
+ * Append the item value if this is not "__custom__".
+ */
+ if (item.value != null && !item.value.equals("__custom__"))
+ s += item.value;
+
+ /*
+ * Append ":" to the description string if needed.
+ */
+ if (!s.isEmpty() && !ret.isEmpty())
+ ret += ":";
+
+ /* Append the item representation */
+ ret += s;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Creates an EditorItem list from a benchmark description string.
+ *
+ * @param benchDesc the benchmark description string
+ *
+ * @return the list
+ */
+ private ArrayList<EditorItem> getEditorItemList(String benchDesc) {
+ String[] benchArray = benchDesc.split(":");
+ String benchName = benchArray[0].trim();
+
+ if (benchName.isEmpty())
+ benchName = "__custom__";
+
+ /* Find SceneInfo from name */
+ SceneInfo sceneInfo = null;
+ for (SceneInfo si: sceneInfoList) {
+ if (si.name.equals(benchName)) {
+ sceneInfo = si;
+ break;
+ }
+ }
+
+ /* If we couldn't find a matching SceneInfo, use __custom__ */
+ if (sceneInfo == null) {
+ for (SceneInfo si: sceneInfoList) {
+ if (si.name.equals("__custom__")) {
+ sceneInfo = si;
+ break;
+ }
+ }
+ }
+
+ ArrayList<EditorItem> l = new ArrayList<EditorItem>();
+
+ /* Append items to the list */
+ if (!sceneInfo.name.equals("__custom__")) {
+ /* Append scene name item */
+ l.add(new EditorItem(null, sceneInfo.name));
+
+ /* Append scene option items */
+ for (SceneInfo.Option opt: sceneInfo.options)
+ l.add(new EditorItem(opt, getOptionValue(benchArray, opt.name)));
+ }
+ else {
+ String desc = new String(benchDesc);
+ if (desc.startsWith("__custom__"))
+ desc = "";
+
+ /* Append scene name item */
+ l.add(new EditorItem(null, sceneInfo.name));
+
+ /* Append scene option items (only one for __custom__) */
+ for (SceneInfo.Option opt: sceneInfo.options)
+ l.add(new EditorItem(opt, desc));
+ }
+
+ return l;
+ }
+
+ /**
+ * Gets a list of information about the available scenes.
+ *
+ * @return the list
+ */
+ private ArrayList<SceneInfo> getSceneInfoList() {
+ ArrayList<SceneInfo> l = new ArrayList<SceneInfo>();
+ SceneInfo customSceneInfo = new SceneInfo("__custom__");
+ customSceneInfo.addOption("__custom__", "Custom benchmark string", "");
+
+ for (Parcelable p: getIntent().getParcelableArrayExtra("scene-info"))
+ l.add((SceneInfo)p);
+
+ /* Add the "__custom__" SceneInfo */
+ l.add(customSceneInfo);
+
+ return l;
+ }
+
+ /**
+ * Gets the array of scene names.
+ *
+ * @return the array
+ */
+ private String[] getSceneNames() {
+ ArrayList<String> l = new ArrayList<String>();
+
+ for (SceneInfo si: sceneInfoList) {
+ if (!si.name.isEmpty())
+ l.add(si.name);
+ }
+
+ String[] a = new String[0];
+ return l.toArray(a);
+ }
+
+
+ static private class EditorItem {
+ SceneInfo.Option option;
+
+ public EditorItem(SceneInfo.Option o, String value) {
+ this.option = o;
+ this.value = value;
+ }
+
+ public String value;
+ }
+
+ /**
+ * A ListView adapter that creates list item views from EditorItems
+ */
+ private class EditorItemAdapter extends ArrayAdapter<EditorItem> {
+ static final int VIEW_TYPE_SCENE_NAME = 0;
+ static final int VIEW_TYPE_SCENE_OPTION = 1;
+ static final int VIEW_TYPE_COUNT = 2;
+
+ public ArrayList<EditorItem> items;
+
+ public EditorItemAdapter(Context context, int textViewResourceId,
+ ArrayList<EditorItem> items)
+ {
+ super(context, textViewResourceId, items);
+ this.items = items;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position == 0)
+ return VIEW_TYPE_SCENE_NAME;
+ else
+ return VIEW_TYPE_SCENE_OPTION;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return VIEW_TYPE_COUNT;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (position == 0)
+ return getViewScene(position, convertView);
+ else
+ return getViewOption(position, convertView);
+ }
+
+ private View getViewScene(int position, View convertView) {
+ /* Get the view/widget to use */
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ v = vi.inflate(R.layout.benchmark_item, null);
+ }
+
+ EditorItem item = items.get(position);
+
+ TextView title = (TextView) v.findViewById(R.id.title);
+ TextView summary = (TextView) v.findViewById(R.id.summary);
+
+ if (title != null)
+ title.setText(item.value);
+ if (summary != null)
+ summary.setText("The scene to use");
+
+ return v;
+ }
+
+ private View getViewOption(int position, View convertView) {
+ /* Get the view/widget to use */
+ View v = convertView;
+ if (v == null) {
+ LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ v = vi.inflate(R.layout.benchmark_item, null);
+ }
+
+ EditorItem item = items.get(position);
+
+ TextView title = (TextView) v.findViewById(R.id.title);
+ TextView summary = (TextView) v.findViewById(R.id.summary);
+ boolean hasUserSetValue = item.value != null;
+ String value = hasUserSetValue ? item.value : item.option.defaultValue;
+
+ if (title != null) {
+ /* If the option has been edited by the user show it with emphasis */
+ SpannableString titleText = new SpannableString(item.option.name + " = " + value);
+ ForegroundColorSpan span = new ForegroundColorSpan(hasUserSetValue ? Color.CYAN : Color.LTGRAY);
+ titleText.setSpan(span, item.option.name.length() + " = ".length(), titleText.length(), 0);
+ title.setText(titleText);
+ }
+
+ if (summary != null)
+ summary.setText(item.option.description);
+
+ return v;
+ }
+ }
}
diff --git a/android/src/org/linaro/glmark2/MainActivity.java b/android/src/org/linaro/glmark2/MainActivity.java
index a04a7ad..a5c9531 100644
--- a/android/src/org/linaro/glmark2/MainActivity.java
+++ b/android/src/org/linaro/glmark2/MainActivity.java
@@ -1,3 +1,24 @@
+/*
+ * Copyright © 2012 Linaro Limited
+ *
+ * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
+ *
+ * glmark2 is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * glmark2. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Alexandros Frantzis
+ */
package org.linaro.glmark2;
import java.util.ArrayList;
@@ -34,6 +55,7 @@
ArrayList<String> benchmarks;
BaseAdapter adapter;
+ SceneInfo[] sceneInfoList;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -93,9 +115,9 @@
}
}
- /**
+ /**
* Initialize the activity.
- *
+ *
* @param savedBenchmarks a list of benchmarks to load the list with (or null)
*/
private void init(ArrayList<String> savedBenchmarks)
@@ -109,6 +131,9 @@
benchmarks = savedBenchmarks;
}
+ /* Get Scene information */
+ sceneInfoList = Glmark2Native.getSceneInfo(getAssets());
+
/* Set up the run button */
Button button = (Button) findViewById(R.id.runButton);
button.setOnClickListener(new View.OnClickListener() {
@@ -128,7 +153,7 @@
adapter = new BenchmarkAdapter(this, R.layout.benchmark_item, benchmarks);
lv.setAdapter(adapter);
- lv.setOnItemClickListener(new OnItemClickListener() {
+ lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
Intent intent = new Intent(MainActivity.this, EditorActivity.class);
String t = benchmarks.get(position);
@@ -136,6 +161,7 @@
t = "";
intent.putExtra("benchmark-text", t);
intent.putExtra("benchmark-pos", position);
+ intent.putExtra("scene-info", sceneInfoList);
startActivityForResult(intent, 1);
}
});
@@ -153,9 +179,9 @@
}
- /**
+ /**
* Perform an action on an listview benchmark item.
- *
+ *
* @param position the position of the item in the listview
* @param action the action to perform
* @param data extra data needed by some actions
@@ -220,7 +246,7 @@
});
}
- /**
+ /**
* A ListView adapter that creates item views from benchmark strings.
*/
private class BenchmarkAdapter extends ArrayAdapter<String> {
@@ -258,4 +284,8 @@
return v;
}
}
+
+ static {
+ System.loadLibrary("glmark2-android");
+ }
}
diff --git a/android/src/org/linaro/glmark2/SceneInfo.java b/android/src/org/linaro/glmark2/SceneInfo.java
index a353c7a..7a85e07 100644
--- a/android/src/org/linaro/glmark2/SceneInfo.java
+++ b/android/src/org/linaro/glmark2/SceneInfo.java
@@ -26,7 +26,7 @@
import java.util.ArrayList;
class SceneInfo implements Parcelable {
- class Option {
+ static class Option {
String name;
String description;
String defaultValue;