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 
26 import android.os.Bundle;
27 import android.app.Activity;
28 import android.app.AlertDialog;
29 import android.app.Dialog;
30 import android.content.Context;
31 import android.content.DialogInterface;
32 import android.content.DialogInterface.OnDismissListener;
33 import android.content.Intent;
34 import android.content.SharedPreferences;
35 import android.preference.PreferenceManager;
36 import android.widget.BaseAdapter;
37 import android.widget.ArrayAdapter;
38 import android.widget.ListView;
39 import android.widget.TextView;
40 import android.widget.Button;
41 import android.widget.EditText;
42 import android.widget.CheckBox;
43 import android.view.KeyEvent;
44 import android.view.LayoutInflater;
45 import android.view.Menu;
46 import android.view.MenuInflater;
47 import android.view.MenuItem;
48 import android.view.View;
49 import android.view.ViewGroup;
50 import android.view.WindowManager;
51 import android.view.inputmethod.EditorInfo;
52 import android.util.Log;
53 import android.widget.AdapterView.OnItemClickListener;
54 import android.widget.AdapterView.OnItemLongClickListener;
55 import android.widget.AdapterView;
56 import android.widget.TextView.OnEditorActionListener;
57 
58 public class MainActivity extends Activity {
59     public static final int DIALOG_ERROR_ID = 0;
60     public static final int DIALOG_BENCHMARK_ACTIONS_ID = 1;
61     public static final int DIALOG_SAVE_LIST_ID = 2;
62     public static final int DIALOG_LOAD_LIST_ID = 3;
63     public static final int DIALOG_DELETE_LIST_ID = 4;
64 
65     public static final int ACTIVITY_GLMARK2_REQUEST_CODE = 1;
66     public static final int ACTIVITY_EDITOR_REQUEST_CODE = 2;
67 
68     /**
69      * The supported benchmark item actions.
70      */
71     public enum BenchmarkItemAction {
72         EDIT, DELETE, CLONE, MOVEUP, MOVEDOWN
73     }
74 
75     BaseAdapter adapter;
76     SceneInfo[] sceneInfoList;
77     BenchmarkListManager benchmarkListManager;
78 
79     @Override
onCreate(Bundle savedInstanceState)80     public void onCreate(Bundle savedInstanceState) {
81         super.onCreate(savedInstanceState);
82         setContentView(R.layout.activity_main);
83         ArrayList<String> savedBenchmarks = null;
84 
85         if (savedInstanceState != null)
86             savedBenchmarks = savedInstanceState.getStringArrayList("benchmarks");
87 
88         init(savedBenchmarks);
89     }
90 
91     @Override
onSaveInstanceState(Bundle outState)92     protected void onSaveInstanceState(Bundle outState) {
93         super.onSaveInstanceState(outState);
94         outState.putStringArrayList("benchmarks", benchmarkListManager.getBenchmarkList());
95     }
96 
97     @Override
onCreateDialog(int id, Bundle bundle)98     protected Dialog onCreateDialog(int id, Bundle bundle) {
99         final CharSequence[] benchmarkActions = {"Delete", "Clone", "Move Up", "Move Down"};
100         final BenchmarkItemAction[] benchmarkActionsId = {
101                 BenchmarkItemAction.DELETE, BenchmarkItemAction.CLONE,
102                 BenchmarkItemAction.MOVEUP, BenchmarkItemAction.MOVEDOWN
103         };
104         final int finalId = id;
105 
106         Dialog dialog;
107 
108         switch (id) {
109             case DIALOG_ERROR_ID:
110                 {
111                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
112                 builder.setMessage(bundle.getString("message") + ": " +
113                                    bundle.getString("detail"));
114                 builder.setCancelable(false);
115                 builder.setPositiveButton("OK", null);
116                 dialog = builder.create();
117                 }
118                 break;
119 
120             case DIALOG_BENCHMARK_ACTIONS_ID:
121                 {
122                 final int benchmarkPos = bundle.getInt("benchmark-pos");
123                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
124                 builder.setTitle("Pick an action");
125                 builder.setItems(benchmarkActions, new DialogInterface.OnClickListener() {
126                     public void onClick(DialogInterface dialog, int item) {
127                         doBenchmarkItemAction(benchmarkPos, benchmarkActionsId[item], null);
128                         dismissDialog(DIALOG_BENCHMARK_ACTIONS_ID);
129                     }
130                 });
131                 dialog = builder.create();
132                 }
133                 break;
134 
135             case DIALOG_SAVE_LIST_ID:
136                 {
137                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
138                 View layout = getLayoutInflater().inflate(R.layout.save_dialog, null);
139                 final EditText input = (EditText) layout.findViewById(R.id.listName);
140                 final CheckBox checkBox = (CheckBox) layout.findViewById(R.id.external);
141 
142                 input.setOnEditorActionListener(new OnEditorActionListener() {
143                     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
144                         if (actionId == EditorInfo.IME_ACTION_DONE ||
145                             (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER &&
146                              event.getAction() == KeyEvent.ACTION_UP))
147                         {
148                             String listName = v.getText().toString();
149                             try {
150                                 benchmarkListManager.saveBenchmarkList(listName,
151                                                                        checkBox.isChecked());
152                             }
153                             catch (Exception ex) {
154                                 Bundle bundle = new Bundle();
155                                 bundle.putString("message", "Cannot save list to file " + listName);
156                                 bundle.putString("detail", ex.getMessage());
157                                 showDialog(DIALOG_ERROR_ID, bundle);
158                             }
159                             dismissDialog(DIALOG_SAVE_LIST_ID);
160                         }
161                         return true;
162                     }
163                 });
164 
165                 builder.setTitle("Save list as");
166                 builder.setView(layout);
167 
168                 dialog = builder.create();
169                 dialog.getWindow().setSoftInputMode(
170                         WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN |
171                         WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
172                         );
173                 }
174                 break;
175 
176             case DIALOG_LOAD_LIST_ID:
177             case DIALOG_DELETE_LIST_ID:
178                 {
179                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
180                 if (id == DIALOG_LOAD_LIST_ID)
181                     builder.setTitle("Load list");
182                 else
183                     builder.setTitle("Delete list");
184                 final String[] savedLists = benchmarkListManager.getSavedLists();
185 
186                 builder.setItems(savedLists, new DialogInterface.OnClickListener() {
187                     public void onClick(DialogInterface dialog, int index) {
188                         String desc = savedLists[index];
189                         String filename = "";
190                         boolean external = false;
191 
192                         if (desc.startsWith("internal/")) {
193                             filename = desc.replace("internal/", "");
194                             external = false;
195                         }
196                         else if (desc.startsWith("external/")) {
197                             filename = desc.replace("external/", "");
198                             external = true;
199                         }
200 
201                         try {
202                             if (finalId == DIALOG_LOAD_LIST_ID) {
203                                 benchmarkListManager.loadBenchmarkList(filename, external);
204                                 adapter.notifyDataSetChanged();
205                             }
206                             else {
207                                 benchmarkListManager.deleteBenchmarkList(filename, external);
208                             }
209 
210                         }
211                         catch (Exception ex) {
212                             Bundle bundle = new Bundle();
213                             if (finalId == DIALOG_LOAD_LIST_ID)
214                                 bundle.putString("message", "Cannot load list " + desc);
215                             else
216                                 bundle.putString("message", "Cannot delete list " + desc);
217                             bundle.putString("detail", ex.getMessage());
218                             showDialog(DIALOG_ERROR_ID, bundle);
219                         }
220                         dismissDialog(finalId);
221                     }
222                 });
223 
224                 dialog = builder.create();
225                 }
226                 break;
227 
228             default:
229                 dialog = null;
230                 break;
231         }
232 
233         if (dialog != null) {
234             dialog.setOnDismissListener(new OnDismissListener() {
235                 public void onDismiss(DialogInterface dialog) {
236                     removeDialog(finalId);
237                 }
238             });
239         }
240 
241         return dialog;
242     }
243 
244     @Override
onCreateOptionsMenu(Menu menu)245     public boolean onCreateOptionsMenu(Menu menu) {
246         MenuInflater inflater = getMenuInflater();
247         inflater.inflate(R.menu.main_options_menu, menu);
248         return true;
249     }
250 
251     @Override
onOptionsItemSelected(MenuItem item)252     public boolean onOptionsItemSelected(MenuItem item) {
253         boolean ret = true;
254 
255         switch (item.getItemId()) {
256             case R.id.save_benchmark_list:
257                 showDialog(DIALOG_SAVE_LIST_ID);
258                 ret = true;
259                 break;
260             case R.id.load_benchmark_list:
261                 showDialog(DIALOG_LOAD_LIST_ID);
262                 ret = true;
263                 break;
264             case R.id.delete_benchmark_list:
265                 showDialog(DIALOG_DELETE_LIST_ID);
266                 ret = true;
267                 break;
268             case R.id.settings:
269                 startActivity(new Intent(MainActivity.this, MainPreferencesActivity.class));
270                 ret = true;
271                 break;
272             case R.id.results:
273                 startActivity(new Intent(MainActivity.this, ResultsActivity.class));
274                 ret = true;
275                 break;
276             case R.id.about:
277                 startActivity(new Intent(MainActivity.this, AboutActivity.class));
278                 ret = true;
279                 break;
280             default:
281                 ret = super.onOptionsItemSelected(item);
282                 break;
283         }
284 
285         return ret;
286     }
287 
288     @Override
onActivityResult(int requestCode, int resultCode, Intent data)289     public void onActivityResult(int requestCode, int resultCode, Intent data) {
290         if (requestCode == ACTIVITY_GLMARK2_REQUEST_CODE)
291         {
292             startActivity(new Intent(this, ResultsActivity.class));
293             return;
294         }
295         else if (requestCode == ACTIVITY_EDITOR_REQUEST_CODE &&
296                  resultCode == RESULT_OK)
297         {
298             String benchmarkText = data.getStringExtra("benchmark-text");
299             int benchmarkPos = data.getIntExtra("benchmark-pos", 0);
300             doBenchmarkItemAction(benchmarkPos, BenchmarkItemAction.EDIT, benchmarkText);
301         }
302     }
303 
304     /**
305      * Initialize the activity.
306      *
307      * @param savedBenchmarks a list of benchmarks to load the list with (or null)
308      */
init(ArrayList<String> savedBenchmarks)309     private void init(ArrayList<String> savedBenchmarks)
310     {
311         /* Initialize benchmark list manager */
312         benchmarkListManager = new BenchmarkListManager(this, savedBenchmarks);
313         final ArrayList<String> benchmarks = benchmarkListManager.getBenchmarkList();
314 
315         /* Get Scene information */
316         sceneInfoList = Glmark2Native.getSceneInfo(getAssets());
317 
318         /* Set up the run button */
319         Button button = (Button) findViewById(R.id.runButton);
320         button.setOnClickListener(new View.OnClickListener() {
321             public void onClick(View v) {
322                 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
323                 Intent intent = new Intent(MainActivity.this, Glmark2Activity.class);
324                 String args = "";
325                 for (int i = 0; i < benchmarks.size() - 1; i++)
326                     args += "-b \"" + benchmarks.get(i) + "\" ";
327                 if (prefs.getBoolean("run_forever", false))
328                     args += "--run-forever ";
329                 if (prefs.getBoolean("log_debug", false))
330                     args += "--debug ";
331                 if (!args.isEmpty())
332                     intent.putExtra("args", args);
333 
334                 if (prefs.getBoolean("show_results", true))
335                     startActivityForResult(intent, ACTIVITY_GLMARK2_REQUEST_CODE);
336                 else
337                     startActivity(intent);
338             }
339         });
340 
341         /* Set up the benchmark list view */
342         ListView lv = (ListView) findViewById(R.id.benchmarkListView);
343         adapter = new BenchmarkAdapter(this, R.layout.list_item, benchmarks);
344         lv.setAdapter(adapter);
345 
346         lv.setOnItemClickListener(new OnItemClickListener() {
347             public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
348                 Intent intent = new Intent(MainActivity.this, EditorActivity.class);
349                 String t = benchmarks.get(position);
350                 if (position == benchmarks.size() - 1)
351                     t = "";
352                 intent.putExtra("benchmark-text", t);
353                 intent.putExtra("benchmark-pos", position);
354                 intent.putExtra("scene-info", sceneInfoList);
355                 startActivityForResult(intent, ACTIVITY_EDITOR_REQUEST_CODE);
356             }
357         });
358 
359         lv.setOnItemLongClickListener(new OnItemLongClickListener() {
360             public boolean onItemLongClick(AdapterView<?> parentView, View childView, int position, long id) {
361                 if (position < benchmarks.size() - 1) {
362                     Bundle bundle = new Bundle();
363                     bundle.putInt("benchmark-pos", position);
364                     showDialog(DIALOG_BENCHMARK_ACTIONS_ID, bundle);
365                 }
366                 return true;
367             }
368         });
369 
370     }
371 
372     /**
373      * Perform an action on an listview benchmark item.
374      *
375      * @param position the position of the item in the listview
376      * @param action the action to perform
377      * @param data extra data needed by some actions
378      */
doBenchmarkItemAction(int position, BenchmarkItemAction action, String data)379     private void doBenchmarkItemAction(int position, BenchmarkItemAction action, String data)
380     {
381         int scrollPosition = position;
382         final ArrayList<String> benchmarks = benchmarkListManager.getBenchmarkList();
383 
384         switch(action) {
385             case EDIT:
386                 if (position == benchmarks.size() - 1) {
387                     benchmarks.add(position, data);
388                     scrollPosition = position + 1;
389                 }
390                 else {
391                     benchmarks.set(position, data);
392                 }
393                 break;
394             case DELETE:
395                 benchmarks.remove(position);
396                 break;
397             case CLONE:
398                 {
399                     String s = benchmarks.get(position);
400                     benchmarks.add(position, s);
401                     scrollPosition = position + 1;
402                 }
403                 break;
404             case MOVEUP:
405                 if (position > 0) {
406                     String up = benchmarks.get(position - 1);
407                     String s = benchmarks.get(position);
408                     benchmarks.set(position - 1, s);
409                     benchmarks.set(position, up);
410                     scrollPosition = position - 1;
411                 }
412                 break;
413             case MOVEDOWN:
414                 if (position < benchmarks.size() - 2) {
415                     String down = benchmarks.get(position + 1);
416                     String s = benchmarks.get(position);
417                     benchmarks.set(position + 1, s);
418                     benchmarks.set(position, down);
419                     scrollPosition = position + 1;
420                 }
421                 break;
422             default:
423                 break;
424         }
425 
426 
427         adapter.notifyDataSetChanged();
428 
429         /* Scroll the list view so that the item of interest remains visible */
430         final int finalScrollPosition = scrollPosition;
431         final ListView lv = (ListView) findViewById(R.id.benchmarkListView);
432         lv.post(new Runnable() {
433             @Override
434             public void run() {
435                 lv.smoothScrollToPosition(finalScrollPosition);
436             }
437         });
438     }
439 
440     /**
441      * A ListView adapter that creates item views from benchmark strings.
442      */
443     private class BenchmarkAdapter extends ArrayAdapter<String> {
444         private ArrayList<String> items;
445 
BenchmarkAdapter(Context context, int textViewResourceId, ArrayList<String> items)446         public BenchmarkAdapter(Context context, int textViewResourceId, ArrayList<String> items) {
447             super(context, textViewResourceId, items);
448             this.items = items;
449         }
450 
451         @Override
getView(int position, View convertView, ViewGroup parent)452         public View getView(int position, View convertView, ViewGroup parent) {
453             /* Get the view/widget to use */
454             View v = convertView;
455             if (v == null) {
456                 LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
457                 v = vi.inflate(R.layout.list_item, null);
458             }
459 
460             /* Split the benchmark into its scene name and its options */
461             String benchmark = items.get(position);
462             String[] ba = benchmark.split(":", 2);
463 
464             if (ba != null) {
465                 TextView title = (TextView) v.findViewById(R.id.title);
466                 TextView summary = (TextView) v.findViewById(R.id.summary);
467                 title.setText("");
468                 summary.setText("");
469 
470                 if (title != null && ba.length > 0)
471                     title.setText(ba[0]);
472                 if (summary != null && ba.length > 1)
473                     summary.setText(ba[1]);
474             }
475             return v;
476         }
477     }
478 
479     static {
480         System.loadLibrary("glmark2-android");
481     }
482 }
483