1 /* 2 * Copyright © 2012 Linaro Limited 3 * 4 * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark. 5 * 6 * glmark2 is free software: you can redistribute it and/or modify it under the 7 * terms of the GNU General Public License as published by the Free Software 8 * Foundation, either version 3 of the License, or (at your option) any later 9 * version. 10 * 11 * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY 12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 * details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * glmark2. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * Authors: 20 * Alexandros Frantzis 21 */ 22 package org.linaro.glmark2; 23 24 import java.util.ArrayList; 25 import java.util.Collections; 26 import java.util.Comparator; 27 28 import android.app.Activity; 29 import android.app.AlertDialog; 30 import android.app.Dialog; 31 import android.content.Context; 32 import android.content.DialogInterface; 33 import android.content.DialogInterface.OnDismissListener; 34 import android.content.Intent; 35 import android.graphics.Color; 36 import android.os.Bundle; 37 import android.os.Parcelable; 38 import android.text.SpannableString; 39 import android.text.style.ForegroundColorSpan; 40 import android.util.Log; 41 import android.view.inputmethod.EditorInfo; 42 import android.view.KeyEvent; 43 import android.view.LayoutInflater; 44 import android.view.View; 45 import android.view.ViewGroup; 46 import android.view.WindowManager; 47 import android.widget.AdapterView; 48 import android.widget.AdapterView.OnItemClickListener; 49 import android.widget.AdapterView.OnItemLongClickListener; 50 import android.widget.ArrayAdapter; 51 import android.widget.Button; 52 import android.widget.EditText; 53 import android.widget.ListView; 54 import android.widget.TextView; 55 import android.widget.TextView.OnEditorActionListener; 56 57 public class EditorActivity extends Activity { 58 public static final int DIALOG_SCENE_NAME_ID = 0; 59 public static final int DIALOG_SCENE_OPTION_TEXT_ID = 1; 60 public static final int DIALOG_SCENE_OPTION_LIST_ID = 2; 61 62 public static final int ITEM_POSITION_SCENE_NAME_HEADER = 0; 63 public static final int ITEM_POSITION_SCENE_NAME = 1; 64 public static final int ITEM_POSITION_SCENE_OPTION_HEADER = 2; 65 public static final int ITEM_POSITION_SCENE_OPTION = 3; 66 67 private EditorItemAdapter adapter; 68 private ArrayList<SceneInfo> sceneInfoList; 69 private String[] sceneNames; 70 71 @Override onCreate(Bundle savedInstanceState)72 public void onCreate(Bundle savedInstanceState) { 73 super.onCreate(savedInstanceState); 74 setContentView(R.layout.activity_editor); 75 76 /* Get information about the available scenes */ 77 sceneInfoList = getSceneInfoList(); 78 sceneNames = getSceneNames(); 79 80 /* Read information sent by the main activity */ 81 final int benchmarkPos = this.getIntent().getIntExtra("benchmark-pos", 0); 82 String benchmarkText = getIntent().getStringExtra("benchmark-text"); 83 if (benchmarkText.isEmpty()) 84 benchmarkText = sceneNames[0]; 85 86 /* Set up the run button */ 87 Button runButton = (Button) findViewById(R.id.runButton); 88 runButton.setOnClickListener(new View.OnClickListener() { 89 public void onClick(View v) { 90 Intent intent = new Intent(EditorActivity.this, Glmark2Activity.class); 91 String args = "-b \"" + getBenchmarkDescriptionText() + "\""; 92 intent.putExtra("args", args); 93 startActivity(intent); 94 } 95 }); 96 97 /* Set up the save button */ 98 Button button = (Button) findViewById(R.id.saveButton); 99 button.setOnClickListener(new View.OnClickListener() { 100 public void onClick(View v) { 101 String newBenchmarkText = getBenchmarkDescriptionText(); 102 Intent intent = new Intent(); 103 intent.putExtra("benchmark-text", newBenchmarkText); 104 intent.putExtra("benchmark-pos", benchmarkPos); 105 setResult(RESULT_OK, intent); 106 finish(); 107 } 108 }); 109 110 /* Set up list view */ 111 ListView lv = (ListView) findViewById(R.id.editorListView); 112 adapter = new EditorItemAdapter(this, R.layout.list_item, 113 getEditorItemList(benchmarkText)); 114 lv.setAdapter(adapter); 115 116 lv.setOnItemClickListener(new OnItemClickListener() { 117 public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) { 118 Bundle bundle = new Bundle(); 119 bundle.putInt("item-pos", position); 120 /* Show the right dialog, depending on the clicked list position */ 121 if (position == ITEM_POSITION_SCENE_NAME) { 122 showDialog(DIALOG_SCENE_NAME_ID, bundle); 123 } 124 else if (position >= ITEM_POSITION_SCENE_OPTION) { 125 String[] values = adapter.getItem(position).option.acceptableValues; 126 if (values.length == 0) 127 showDialog(DIALOG_SCENE_OPTION_TEXT_ID, bundle); 128 else 129 showDialog(DIALOG_SCENE_OPTION_LIST_ID, bundle); 130 } 131 } 132 }); 133 134 lv.setOnItemLongClickListener(new OnItemLongClickListener() { 135 public boolean onItemLongClick(AdapterView<?> parentView, View childView, int position, long id) { 136 /* Reset the value of the long-clicked option */ 137 if (position >= ITEM_POSITION_SCENE_OPTION) { 138 EditorItem item = adapter.getItem(position); 139 item.value = null; 140 adapter.notifyDataSetChanged(); 141 } 142 return true; 143 } 144 }); 145 } 146 147 @Override onCreateDialog(int id, Bundle bundle)148 protected Dialog onCreateDialog(int id, Bundle bundle) { 149 final int itemPos = bundle.getInt("item-pos"); 150 Dialog dialog; 151 final int finalId = id; 152 153 switch (id) { 154 case DIALOG_SCENE_NAME_ID: 155 { 156 AlertDialog.Builder builder = new AlertDialog.Builder(this); 157 builder.setTitle("Pick a scene"); 158 builder.setItems(sceneNames, new DialogInterface.OnClickListener() { 159 public void onClick(DialogInterface dialog, int item) { 160 adapter.clear(); 161 for (EditorItem ei: getEditorItemList(sceneNames[item])) 162 adapter.add(ei); 163 adapter.notifyDataSetChanged(); 164 dismissDialog(DIALOG_SCENE_NAME_ID); 165 } 166 }); 167 dialog = builder.create(); 168 } 169 break; 170 171 case DIALOG_SCENE_OPTION_TEXT_ID: 172 { 173 AlertDialog.Builder builder = new AlertDialog.Builder(this); 174 final EditorItem item = adapter.getItem(itemPos); 175 final EditText input = new EditText(this); 176 input.setSingleLine(true); 177 if (item.value != null) 178 input.setText(item.value); 179 180 input.setOnEditorActionListener(new OnEditorActionListener() { 181 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 182 if (actionId == EditorInfo.IME_ACTION_DONE || 183 (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && 184 event.getAction() == KeyEvent.ACTION_UP)) 185 { 186 item.value = v.getText().toString(); 187 adapter.notifyDataSetChanged(); 188 dismissDialog(DIALOG_SCENE_OPTION_TEXT_ID); 189 } 190 return true; 191 } 192 }); 193 builder.setTitle(item.option.name + ": " + item.option.description); 194 dialog = builder.create(); 195 ((AlertDialog)dialog).setView(input, 15, 6, 15, 6); 196 dialog.getWindow().setSoftInputMode( 197 WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN | 198 WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE 199 ); 200 201 } 202 break; 203 204 case DIALOG_SCENE_OPTION_LIST_ID: 205 { 206 AlertDialog.Builder builder = new AlertDialog.Builder(this); 207 final EditorItem item = adapter.getItem(itemPos); 208 builder.setTitle(item.option.name + ": " + item.option.description); 209 210 builder.setItems(item.option.acceptableValues, new DialogInterface.OnClickListener() { 211 public void onClick(DialogInterface dialog, int index) { 212 item.value = item.option.acceptableValues[index]; 213 adapter.notifyDataSetChanged(); 214 dismissDialog(DIALOG_SCENE_OPTION_LIST_ID); 215 } 216 }); 217 218 dialog = builder.create(); 219 } 220 break; 221 222 default: 223 dialog = null; 224 break; 225 } 226 227 if (dialog != null) { 228 dialog.setOnDismissListener(new OnDismissListener() { 229 public void onDismiss(DialogInterface dialog) { 230 removeDialog(finalId); 231 } 232 }); 233 } 234 235 return dialog; 236 } 237 238 /** 239 * Gets the value of an option. 240 * 241 * @param benchArray an array of option strings ("opt=val") 242 * @param opt the options to get the value of 243 * 244 * @return the value or null 245 */ getOptionValue(String[] benchArray, String opt)246 private String getOptionValue(String[] benchArray, String opt) { 247 String ret = null; 248 249 /* Search from the end to the beginning */ 250 for (int n = benchArray.length - 1; n >= 0; n--) { 251 String s = benchArray[n].trim(); 252 if (s.startsWith(opt + "=")) { 253 int i = s.indexOf('='); 254 if (i >= 0 && i + 1 < s.length()) { 255 ret = s.substring(i + 1).trim(); 256 break; 257 } 258 } 259 } 260 261 return ret; 262 } 263 264 /** 265 * Gets the benchmark description string of the current editing state. 266 * 267 * @return the string 268 */ getBenchmarkDescriptionText()269 private String getBenchmarkDescriptionText() { 270 String ret = ""; 271 272 for (int i = 0; i < adapter.getCount(); i++) { 273 /* Convert each list item to a proper string representation */ 274 EditorItem item = adapter.getItem(i); 275 if (item == null) 276 continue; 277 278 String s = ""; 279 280 /* 281 * Append "opt=" if this is an option item, except the 282 * "__custom__" item. 283 */ 284 if (item.option != null && item.value != null && 285 !item.option.name.equals("__custom__")) 286 { 287 s += item.option.name + "="; 288 } 289 290 /* 291 * Append the item value if this is not "__custom__". 292 */ 293 if (item.value != null && !item.value.equals("__custom__")) 294 s += item.value; 295 296 /* 297 * Append ":" to the description string if needed. 298 */ 299 if (!s.isEmpty() && !ret.isEmpty()) 300 ret += ":"; 301 302 /* Append the item representation */ 303 ret += s; 304 } 305 306 return ret; 307 } 308 309 /** 310 * Creates an EditorItem list from a benchmark description string. 311 * 312 * @param benchDesc the benchmark description string 313 * 314 * @return the list 315 */ getEditorItemList(String benchDesc)316 private ArrayList<EditorItem> getEditorItemList(String benchDesc) { 317 String[] benchArray = benchDesc.split(":"); 318 String benchName = benchArray[0].trim(); 319 320 if (benchName.isEmpty()) 321 benchName = "__custom__"; 322 323 /* Find SceneInfo from name */ 324 SceneInfo sceneInfo = null; 325 for (SceneInfo si: sceneInfoList) { 326 if (si.name.equals(benchName)) { 327 sceneInfo = si; 328 break; 329 } 330 } 331 332 /* If we couldn't find a matching SceneInfo, use __custom__ */ 333 if (sceneInfo == null) { 334 for (SceneInfo si: sceneInfoList) { 335 if (si.name.equals("__custom__")) { 336 sceneInfo = si; 337 break; 338 } 339 } 340 } 341 342 ArrayList<EditorItem> l = new ArrayList<EditorItem>(); 343 344 /* Append null item for Scene header */ 345 l.add(null); 346 347 /* Append scene name item */ 348 l.add(new EditorItem(null, sceneInfo.name)); 349 350 /* Append null item for Options header */ 351 l.add(null); 352 353 /* Append items to the list */ 354 if (!sceneInfo.name.equals("__custom__")) { 355 /* Append scene option items */ 356 for (SceneInfo.Option opt: sceneInfo.options) 357 l.add(new EditorItem(opt, getOptionValue(benchArray, opt.name))); 358 } 359 else { 360 String desc = new String(benchDesc); 361 if (desc.startsWith("__custom__")) 362 desc = ""; 363 364 /* Append scene option items (only one for __custom__) */ 365 for (SceneInfo.Option opt: sceneInfo.options) 366 l.add(new EditorItem(opt, desc)); 367 } 368 369 return l; 370 } 371 372 /** 373 * Gets a list of information about the available scenes. 374 * 375 * @return the list 376 */ getSceneInfoList()377 private ArrayList<SceneInfo> getSceneInfoList() { 378 ArrayList<SceneInfo> l = new ArrayList<SceneInfo>(); 379 SceneInfo customSceneInfo = new SceneInfo("__custom__"); 380 customSceneInfo.addOption("__custom__", "Custom benchmark string", "", new String[0]); 381 382 for (Parcelable p: getIntent().getParcelableArrayExtra("scene-info")) 383 l.add((SceneInfo)p); 384 385 /* Sort SceneInfo list by name */ 386 Collections.sort(l, new Comparator<SceneInfo>() { 387 public int compare(SceneInfo s1, SceneInfo s2) { 388 return s1.name.compareTo(s2.name); 389 } 390 }); 391 392 /* Add the "__custom__" SceneInfo */ 393 l.add(customSceneInfo); 394 395 return l; 396 } 397 398 /** 399 * Gets the array of scene names. 400 * 401 * @return the array 402 */ getSceneNames()403 private String[] getSceneNames() { 404 ArrayList<String> l = new ArrayList<String>(); 405 406 for (SceneInfo si: sceneInfoList) { 407 if (!si.name.isEmpty()) 408 l.add(si.name); 409 } 410 411 String[] a = new String[0]; 412 return l.toArray(a); 413 } 414 415 416 static private class EditorItem { 417 SceneInfo.Option option; 418 EditorItem(SceneInfo.Option o, String value)419 public EditorItem(SceneInfo.Option o, String value) { 420 this.option = o; 421 this.value = value; 422 } 423 424 public String value; 425 } 426 427 /** 428 * A ListView adapter that creates list item views from EditorItems 429 */ 430 private class EditorItemAdapter extends ArrayAdapter<EditorItem> { 431 static final int VIEW_TYPE_HEADER = 0; 432 static final int VIEW_TYPE_SCENE_NAME = 1; 433 static final int VIEW_TYPE_SCENE_OPTION = 2; 434 static final int VIEW_TYPE_COUNT = 3; 435 436 public ArrayList<EditorItem> items; 437 EditorItemAdapter(Context context, int textViewResourceId, ArrayList<EditorItem> items)438 public EditorItemAdapter(Context context, int textViewResourceId, 439 ArrayList<EditorItem> items) 440 { 441 super(context, textViewResourceId, items); 442 this.items = items; 443 } 444 445 @Override isEnabled(int position)446 public boolean isEnabled(int position) { 447 return position == ITEM_POSITION_SCENE_NAME || 448 position >= ITEM_POSITION_SCENE_OPTION; 449 } 450 451 @Override getItemViewType(int position)452 public int getItemViewType(int position) { 453 if (position == ITEM_POSITION_SCENE_NAME) 454 return VIEW_TYPE_SCENE_NAME; 455 else if (position >= ITEM_POSITION_SCENE_OPTION) 456 return VIEW_TYPE_SCENE_OPTION; 457 else 458 return VIEW_TYPE_HEADER; 459 } 460 461 @Override getViewTypeCount()462 public int getViewTypeCount() { 463 return VIEW_TYPE_COUNT; 464 } 465 466 @Override getView(int position, View convertView, ViewGroup parent)467 public View getView(int position, View convertView, ViewGroup parent) { 468 int viewType = getItemViewType(position); 469 View v = null; 470 471 if (viewType == VIEW_TYPE_HEADER) 472 v = getViewHeader(position, convertView); 473 else if (viewType == VIEW_TYPE_SCENE_NAME) 474 v = getViewScene(position, convertView); 475 else if (viewType == VIEW_TYPE_SCENE_OPTION) 476 v = getViewOption(position, convertView); 477 478 return v; 479 } 480 getViewHeader(int position, View convertView)481 private View getViewHeader(int position, View convertView) { 482 /* Get the view/widget to use */ 483 View v = convertView; 484 if (v == null) { 485 LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 486 v = vi.inflate(R.layout.list_header, null); 487 } 488 489 TextView tv = (TextView) v; 490 491 if (position == ITEM_POSITION_SCENE_NAME_HEADER) 492 tv.setText("Scene"); 493 else if (position == ITEM_POSITION_SCENE_OPTION_HEADER) 494 tv.setText("Options"); 495 496 return tv; 497 } 498 getViewScene(int position, View convertView)499 private View getViewScene(int position, View convertView) { 500 /* Get the view/widget to use */ 501 View v = convertView; 502 if (v == null) { 503 LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 504 v = vi.inflate(R.layout.list_item, null); 505 } 506 507 EditorItem item = items.get(position); 508 509 TextView title = (TextView) v.findViewById(R.id.title); 510 TextView summary = (TextView) v.findViewById(R.id.summary); 511 512 if (title != null) 513 title.setText(item.value); 514 if (summary != null) 515 summary.setText("The scene to use"); 516 517 return v; 518 } 519 getViewOption(int position, View convertView)520 private View getViewOption(int position, View convertView) { 521 /* Get the view/widget to use */ 522 View v = convertView; 523 if (v == null) { 524 LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 525 v = vi.inflate(R.layout.list_item, null); 526 } 527 528 EditorItem item = items.get(position); 529 530 TextView title = (TextView) v.findViewById(R.id.title); 531 TextView summary = (TextView) v.findViewById(R.id.summary); 532 boolean hasUserSetValue = item.value != null; 533 String value = hasUserSetValue ? item.value : item.option.defaultValue; 534 535 if (title != null) { 536 /* If the option has been edited by the user show it with emphasis */ 537 SpannableString titleText = new SpannableString(item.option.name + " = " + value); 538 ForegroundColorSpan span = new ForegroundColorSpan(hasUserSetValue ? Color.CYAN : Color.LTGRAY); 539 titleText.setSpan(span, item.option.name.length() + " = ".length(), titleText.length(), 0); 540 title.setText(titleText); 541 } 542 543 if (summary != null) 544 summary.setText(item.option.description); 545 546 return v; 547 } 548 } 549 } 550