Android: Implement "Save list" option menu action.
diff --git a/android/res/layout/save_dialog.xml b/android/res/layout/save_dialog.xml
new file mode 100644
index 0000000..1074b52
--- /dev/null
+++ b/android/res/layout/save_dialog.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical" >
+
+    <RelativeLayout android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="15dip"
+                    android:layout_marginRight="15dip"
+                    android:layout_marginTop="6dip"
+                    android:layout_marginBottom="6dip"
+                    android:layout_weight="1">
+
+        <EditText android:id="@+id/listName"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content" />
+
+        <CheckBox android:id="@+id/external"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_alignLeft="@id/listName"
+                  android:layout_below="@id/listName"
+                  android:text="@string/externalSaveDialogText"/>
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
index 2391f03..fb53791 100644
--- a/android/res/values/strings.xml
+++ b/android/res/values/strings.xml
@@ -10,4 +10,6 @@
     <string name="saveMainOptionsText">Save list</string>
     <string name="loadMainOptionsText">Load list</string>
     <string name="aboutMainOptionsText">About</string>
+
+    <string name="externalSaveDialogText">Save to external storage</string>
 </resources>
diff --git a/android/src/org/linaro/glmark2/MainActivity.java b/android/src/org/linaro/glmark2/MainActivity.java
index e5d3d4a..a1725a2 100644
--- a/android/src/org/linaro/glmark2/MainActivity.java
+++ b/android/src/org/linaro/glmark2/MainActivity.java
@@ -22,8 +22,10 @@
 package org.linaro.glmark2;
 
 import java.util.ArrayList;
+import java.io.*;
 
 import android.os.Bundle;
+import android.os.Environment;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -36,19 +38,27 @@
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Button;
+import android.widget.EditText;
+import android.widget.CheckBox;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
 import android.util.Log;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.AdapterView;
+import android.widget.TextView.OnEditorActionListener;
 
 public class MainActivity extends Activity {
-    public static final int DIALOG_BENCHMARK_ACTIONS_ID = 0;
+    public static final int DIALOG_ERROR_ID = 0;
+    public static final int DIALOG_BENCHMARK_ACTIONS_ID = 1;
+    public static final int DIALOG_SAVE_LIST_ID = 2;
 
     /**
      * The supported benchmark item actions.
@@ -86,13 +96,25 @@
                 BenchmarkItemAction.DELETE, BenchmarkItemAction.CLONE,
                 BenchmarkItemAction.MOVEUP, BenchmarkItemAction.MOVEDOWN
         };
-        final int benchmarkPos = bundle.getInt("benchmark-pos");
         final int finalId = id;
 
         Dialog dialog;
 
         switch (id) {
+            case DIALOG_ERROR_ID:
+                {
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                builder.setMessage(bundle.getString("message") + ": " +
+                                   bundle.getString("detail"));
+                builder.setCancelable(false);
+                builder.setPositiveButton("OK", null);
+                dialog = builder.create();
+                }
+                break;
+
             case DIALOG_BENCHMARK_ACTIONS_ID:
+                {
+                final int benchmarkPos = bundle.getInt("benchmark-pos");
                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
                 builder.setTitle("Pick an action");
                 builder.setItems(benchmarkActions, new DialogInterface.OnClickListener() {
@@ -102,6 +124,34 @@
                     }
                 });
                 dialog = builder.create();
+                }
+                break;
+
+            case DIALOG_SAVE_LIST_ID:
+                {
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                View layout = getLayoutInflater().inflate(R.layout.save_dialog, null);
+                final EditText input = (EditText) layout.findViewById(R.id.listName);
+                final CheckBox checkBox = (CheckBox) layout.findViewById(R.id.external);
+
+                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))
+                        {
+                            saveBenchmarkList(v.getText().toString(), checkBox.isChecked());
+                            dismissDialog(DIALOG_SAVE_LIST_ID);
+                        }
+                        return true;
+                    }
+                });
+
+                builder.setTitle("Save list as");
+                builder.setView(layout);
+
+                dialog = builder.create();
+                }
                 break;
 
             default:
@@ -133,6 +183,7 @@
 
         switch (item.getItemId()) {
             case R.id.save_benchmark_list:
+                showDialog(DIALOG_SAVE_LIST_ID);
                 ret = true;
                 break;
             case R.id.load_benchmark_list:
@@ -289,6 +340,50 @@
         });
     }
 
+    private File getSavedListPath(boolean external) {
+        File f = null;
+
+        if (external) {
+            String state = Environment.getExternalStorageState();
+            if (!Environment.MEDIA_MOUNTED.equals(state))
+                return null;
+            f = getExternalFilesDir(null);
+        }
+        else {
+            f = getFilesDir();
+        }
+
+        if (f != null)
+            f = new File(f, "lists");
+
+        return f;
+    }
+
+    private void saveBenchmarkList(String listName, boolean external) {
+        try {
+            File listPath = getSavedListPath(external);
+            if (listPath == null)
+                throw new Exception("External storage not present");
+
+            listPath.mkdirs();
+
+            File f = new File(listPath, listName);
+
+            BufferedWriter out = new BufferedWriter(new FileWriter(f));
+            for (int i = 0; i < benchmarks.size() - 1; i++) {
+                out.write(benchmarks.get(i));
+                out.newLine();
+            }
+            out.close();
+        }
+        catch (Exception ex) {
+            Bundle bundle = new Bundle();
+            bundle.putString("message", "Cannot save list to file " + listName);
+            bundle.putString("detail", ex.getMessage());
+            showDialog(DIALOG_ERROR_ID, bundle);
+        }
+    }
+
     /**
      * A ListView adapter that creates item views from benchmark strings.
      */