<commit_before>package net.af0.sesame;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.content.FileProvider;
import android.text.InputType;
import android.util.Log;
import android.widget.EditText;

import net.sqlcipher.database.SQLiteException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;

class Common {
    static boolean ExportKeys(Context ctx) {
        File dst;
        try {
            String exportName = String.format(Constants.KEY_EXPORT_FILE,
                    new SimpleDateFormat(Constants.KEY_EXPORT_DATE_FORMAT).format(
                            Calendar.getInstance().getTime())
            );
            dst = new File(ctx.getCacheDir(), exportName);
            FileOutputStream dstStr = new FileOutputStream(dst);
            SQLCipherDatabase.ExportDatabase(ctx, dstStr);
        } catch (java.io.IOException e) {
            Log.e("EXPORT", e.toString());
            DisplayException(ctx, ctx.getString(R.string.export_keys_failure_title), e);
            return false;
        }
        Uri contentUri = FileProvider.getUriForFile(ctx, Constants.KEY_EXPORT_URI, dst);
        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
        shareIntent.setType(Constants.KEY_EXPORT_MIME);
        ctx.startActivity(Intent.createChooser(shareIntent, ctx.getResources().getText(
                R.string.action_export)).setFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION));
        return true;
    }

    static void onImportKeysResult(final Context ctx, Intent data, final Runnable importCallback) {
        final Uri uri = data.getData();
        final InputStream src;
        final OutputStream os;
        final File dst;
        try {
            src = ctx.getContentResolver().openInputStream(uri);
            dst = File.createTempFile(Constants.KEY_IMPORT_TMPNAME, Constants.KEY_IMPORT_SUFFIX,
                    ctx.getCacheDir());
            os = new FileOutputStream(dst, false);
            int l;
            byte[] buf = new byte[1024];
            while ((l = src.read(buf)) != -1) {
                os.write(buf, 0, l);
            }
        } catch (IOException e) {
            Log.e("IMPORT", e.toString());
            DisplayException(ctx, ctx.getString(R.string.import_keys_failure_title), e);
            return;
        }

        // Get password.
        final EditText passwordText = new EditText(ctx);
        passwordText.setInputType(InputType.TYPE_CLASS_TEXT |
                InputType.TYPE_TEXT_VARIATION_PASSWORD);
        AlertDialog.Builder alert = new AlertDialog.Builder(ctx);
        alert.setTitle(ctx.getString(R.string.title_enter_password));
        alert.setMessage(ctx.getString(R.string.import_database_password_message));
        alert.setView(passwordText);
        alert.setPositiveButton(R.string.action_unlock, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                try {
                    char[] password = new char[passwordText.length()];
                    passwordText.getText().getChars(0, password.length, password, 0);
                    SQLCipherDatabase.ImportDatabase(ctx, dst.getAbsolutePath(), password);
                    if (importCallback != null) {
                        importCallback.run();
                    }
                } catch (SQLiteException e) {
                    Log.e("IMPORT", e.toString());
                    DisplayException(ctx, ctx.getString(R.string.import_keys_failure_title), e);
                } catch (IOException e) {
                    Log.e("IMPORT", e.toString());
                    DisplayException(ctx, ctx.getString(R.string.import_keys_failure_title), e);
                }
            }
        });
        alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                // Return...
            }
        });
        alert.show();
    }

    static void StartImportKeys(Activity ctx) {
        // TODO: show a progress spinner here.
        Intent importIntent = new Intent();
        importIntent.setAction(Intent.ACTION_GET_CONTENT);
        importIntent.setType("*/*");
        ctx.startActivityForResult(importIntent, Constants.IMPORT_DATABASE_RESULT);
    }

    static void DisplayException(Context ctx, String title, Exception e) {
        if (ctx == null) {
            return;
        }
        new AlertDialog.Builder(ctx)
                .setTitle(title)
                .setMessage(e.getLocalizedMessage())
                .setNeutralButton(ctx.getString(R.string.dismiss), null)
                .create().show();
    }
}
<commit_msg>Improve import UI: async import, progress spinner.<commit_after>package net.af0.sesame;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v4.content.FileProvider;
import android.text.InputType;
import android.util.Log;
import android.widget.EditText;

import net.sqlcipher.database.SQLiteException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;

class Common {
    static boolean ExportKeys(Context ctx) {
        File dst;
        try {
            String exportName = String.format(Constants.KEY_EXPORT_FILE,
                    new SimpleDateFormat(Constants.KEY_EXPORT_DATE_FORMAT).format(
                            Calendar.getInstance().getTime())
            );
            dst = new File(ctx.getCacheDir(), exportName);
            FileOutputStream dstStr = new FileOutputStream(dst);
            SQLCipherDatabase.ExportDatabase(ctx, dstStr);
        } catch (java.io.IOException e) {
            Log.e("EXPORT", e.toString());
            DisplayException(ctx, ctx.getString(R.string.export_keys_failure_title), e);
            return false;
        }
        Uri contentUri = FileProvider.getUriForFile(ctx, Constants.KEY_EXPORT_URI, dst);
        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
        shareIntent.setType(Constants.KEY_EXPORT_MIME);
        ctx.startActivity(Intent.createChooser(shareIntent, ctx.getResources().getText(
                R.string.action_export)).setFlags(
                Intent.FLAG_GRANT_READ_URI_PERMISSION));
        return true;
    }

    static void onImportKeysResult(final Activity ctx, Intent data, final Runnable importCallback) {
        final Uri uri = data.getData();
        final InputStream src;
        final OutputStream os;
        final File dst;
        try {
            src = ctx.getContentResolver().openInputStream(uri);
            dst = File.createTempFile(Constants.KEY_IMPORT_TMPNAME, Constants.KEY_IMPORT_SUFFIX,
                    ctx.getCacheDir());
            os = new FileOutputStream(dst, false);
            int l;
            byte[] buf = new byte[1024];
            while ((l = src.read(buf)) != -1) {
                os.write(buf, 0, l);
            }
        } catch (IOException e) {
            Log.e("IMPORT", e.toString());
            DisplayException(ctx, ctx.getString(R.string.import_keys_failure_title), e);
            return;
        }

        // Get password.
        final EditText passwordText = new EditText(ctx);
        passwordText.setInputType(InputType.TYPE_CLASS_TEXT |
                InputType.TYPE_TEXT_VARIATION_PASSWORD);
        final ProgressDialog progress = new ProgressDialog(ctx);
        progress.setTitle(R.string.unlock_progress_unlocking);
        AlertDialog.Builder alert = new AlertDialog.Builder(ctx);
        alert.setTitle(ctx.getString(R.string.title_enter_password));
        alert.setMessage(ctx.getString(R.string.import_database_password_message));
        alert.setView(passwordText);
        alert.setPositiveButton(R.string.action_unlock, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                final char[] password = new char[passwordText.length()];
                passwordText.getText().getChars(0, password.length, password, 0);
                AsyncTask<Void, Void, Boolean> importTask = new AsyncTask<Void, Void, Boolean>() {
                    Exception exception;

                    @Override
                    protected Boolean doInBackground(Void... params) {
                        boolean success = false;
                        ctx.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                progress.show();
                            }
                        });
                        try {
                            SQLCipherDatabase.ImportDatabase(ctx, dst.getAbsolutePath(), password);
                            success = true;
                        } catch (SQLiteException e) {
                            Log.e("IMPORT", e.toString());
                            exception = e;
                        } catch (IOException e) {
                            Log.e("IMPORT", e.toString());
                            exception = e;
                        }
                        return success;
                    }

                    @Override
                    protected void onPostExecute(final Boolean success) {
                        progress.dismiss();
                        if (success) {
                            if (importCallback != null) {
                                importCallback.run();
                            }
                            return;
                        } else {
                            Log.w("Importing database", exception.toString());
                            DisplayException(ctx, ctx.getString(R.string.import_keys_failure_title),
                                    exception);
                        }
                    }

                    @Override
                    protected void onCancelled() {
                    }
                };
                importTask.execute();
            }
        });
        alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                // Return...
            }
        });
        alert.show();
    }

    static void StartImportKeys(Activity ctx) {
        Intent importIntent = new Intent();
        importIntent.setAction(Intent.ACTION_GET_CONTENT);
        importIntent.setType("*/*");
        ctx.startActivityForResult(importIntent, Constants.IMPORT_DATABASE_RESULT);
    }

    static void DisplayException(Context ctx, String title, Exception e) {
        if (ctx == null) {
            return;
        }
        new AlertDialog.Builder(ctx)
                .setTitle(title)
                .setMessage(e.getLocalizedMessage())
                .setNeutralButton(ctx.getString(R.string.dismiss), null)
                .create().show();
    }
}

{'fraction_non_alphanumeric': 0.09687606691703653, 'fraction_numerical': 0.001707067258449983, 'mean_word_length': 1.9060019841269842, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4257789', 'n_tokens_mistral': 3010, 'n_tokens_neox': 2888, 'n_words': 566}