com.farmerbb.notepad.activity.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.farmerbb.notepad.activity.MainActivity.java

Source

/* Copyright 2014 Braden Farmer
 * Copyright 2015 Sean93Park
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.farmerbb.notepad.activity;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintManager;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.provider.DocumentFile;
import android.util.Base64;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;

import com.farmerbb.notepad.R;
import com.farmerbb.notepad.fragment.NoteEditFragment;
import com.farmerbb.notepad.fragment.NoteListFragment;
import com.farmerbb.notepad.fragment.NoteViewFragment;
import com.farmerbb.notepad.fragment.WelcomeFragment;
import com.farmerbb.notepad.fragment.dialog.BackButtonDialogFragment;
import com.farmerbb.notepad.fragment.dialog.DeleteDialogFragment;
import com.farmerbb.notepad.fragment.dialog.FirstRunDialogFragment;
import com.farmerbb.notepad.fragment.dialog.SaveButtonDialogFragment;
import com.farmerbb.notepad.util.WebViewInitState;

import org.apache.commons.lang3.StringUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

import us.feras.mdv.MarkdownView;

public class MainActivity extends NotepadBaseActivity implements BackButtonDialogFragment.Listener,
        DeleteDialogFragment.Listener, SaveButtonDialogFragment.Listener, FirstRunDialogFragment.Listener,
        NoteListFragment.Listener, NoteEditFragment.Listener, NoteViewFragment.Listener {

    Object[] filesToExport;
    Object[] filesToDelete;
    int fileBeingExported;
    boolean successful = true;

    private ArrayList<String> cab = new ArrayList<>();
    private boolean inCabMode = false;

    public static final int IMPORT = 42;
    public static final int EXPORT = 43;
    public static final int EXPORT_TREE = 44;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // Set action bar elevation
            getSupportActionBar().setElevation(getResources().getDimensionPixelSize(R.dimen.action_bar_elevation));
        }

        // Show dialog if this is the user's first time running Notepad
        SharedPreferences prefMain = getPreferences(Context.MODE_PRIVATE);
        if (prefMain.getInt("first-run", 0) == 0) {
            // Show welcome dialog
            if (getSupportFragmentManager().findFragmentByTag("firstrunfragment") == null) {
                DialogFragment firstRun = new FirstRunDialogFragment();
                firstRun.show(getSupportFragmentManager(), "firstrunfragment");
            }
        } else {
            // The following code is only present to support existing users of Notepad on Google Play
            // and can be removed if using this source code for a different app

            // Convert old preferences to new ones
            SharedPreferences pref = getSharedPreferences(getPackageName() + "_preferences", Context.MODE_PRIVATE);
            if (prefMain.getInt("sort-by", -1) == 0) {
                SharedPreferences.Editor editor = pref.edit();
                SharedPreferences.Editor editorMain = prefMain.edit();

                editor.putString("sort_by", "date");
                editorMain.putInt("sort-by", -1);

                editor.apply();
                editorMain.apply();
            } else if (prefMain.getInt("sort-by", -1) == 1) {
                SharedPreferences.Editor editor = pref.edit();
                SharedPreferences.Editor editorMain = prefMain.edit();

                editor.putString("sort_by", "name");
                editorMain.putInt("sort-by", -1);

                editor.apply();
                editorMain.apply();
            }

            if (pref.getString("font_size", "null").equals("null")) {
                SharedPreferences.Editor editor = pref.edit();
                editor.putString("font_size", "large");
                editor.apply();
            }

            // Rename any saved drafts from 1.3.x
            File oldDraft = new File(getFilesDir() + File.separator + "draft");
            File newDraft = new File(getFilesDir() + File.separator + String.valueOf(System.currentTimeMillis()));

            if (oldDraft.exists())
                oldDraft.renameTo(newDraft);
        }

        // Begin a new FragmentTransaction
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // This fragment shows NoteListFragment as a sidebar (only seen in tablet mode landscape)
        if (!(getSupportFragmentManager().findFragmentById(R.id.noteList) instanceof NoteListFragment))
            transaction.replace(R.id.noteList, new NoteListFragment(), "NoteListFragment");

        // This fragment shows NoteListFragment in the main screen area (only seen on phones and tablet mode portrait),
        // but only if it doesn't already contain NoteViewFragment or NoteEditFragment.
        // If NoteListFragment is already showing in the sidebar, use WelcomeFragment instead
        if (!((getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteEditFragment)
                || (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteViewFragment))) {
            if ((getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) == null
                    && findViewById(R.id.layoutMain).getTag().equals("main-layout-large"))
                    || ((getSupportFragmentManager()
                            .findFragmentById(R.id.noteViewEdit) instanceof NoteListFragment)
                            && findViewById(R.id.layoutMain).getTag().equals("main-layout-large")))
                transaction.replace(R.id.noteViewEdit, new WelcomeFragment(), "NoteListFragment");
            else if (findViewById(R.id.layoutMain).getTag().equals("main-layout-normal"))
                transaction.replace(R.id.noteViewEdit, new NoteListFragment(), "NoteListFragment");
        }

        // Commit fragment transaction
        transaction.commit();

        if (savedInstanceState != null) {
            ArrayList<String> filesToExportList = savedInstanceState.getStringArrayList("files_to_export");
            if (filesToExportList != null)
                filesToExport = filesToExportList.toArray();

            ArrayList<String> filesToDeleteList = savedInstanceState.getStringArrayList("files_to_delete");
            if (filesToDeleteList != null)
                filesToDelete = filesToDeleteList.toArray();

            ArrayList<String> savedCab = savedInstanceState.getStringArrayList("cab");
            if (savedCab != null) {
                inCabMode = true;
                cab = savedCab;
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        WebViewInitState wvState = WebViewInitState.getInstance();
        wvState.initialize(this);
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (!inCabMode)
            cab.clear();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
    }

    // Keyboard shortcuts
    @Override
    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
        super.dispatchKeyShortcutEvent(event);
        if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
            if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteListFragment) {
                NoteListFragment fragment = (NoteListFragment) getSupportFragmentManager()
                        .findFragmentByTag("NoteListFragment");
                fragment.dispatchKeyShortcutEvent(event.getKeyCode());
            } else if (getSupportFragmentManager()
                    .findFragmentById(R.id.noteViewEdit) instanceof NoteViewFragment) {
                NoteViewFragment fragment = (NoteViewFragment) getSupportFragmentManager()
                        .findFragmentByTag("NoteViewFragment");
                fragment.dispatchKeyShortcutEvent(event.getKeyCode());
            } else if (getSupportFragmentManager()
                    .findFragmentById(R.id.noteViewEdit) instanceof NoteEditFragment) {
                NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                        .findFragmentByTag("NoteEditFragment");
                fragment.dispatchKeyShortcutEvent(event.getKeyCode());
            } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof WelcomeFragment) {
                WelcomeFragment fragment = (WelcomeFragment) getSupportFragmentManager()
                        .findFragmentByTag("NoteListFragment");
                fragment.dispatchKeyShortcutEvent(event.getKeyCode());
            }

            return true;
        }
        return super.dispatchKeyShortcutEvent(event);
    }

    @Override
    public void onDeleteDialogPositiveClick() {
        if (filesToDelete != null) {
            reallyDeleteNotes();
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteViewFragment) {
            NoteViewFragment fragment = (NoteViewFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteViewFragment");
            fragment.onDeleteDialogPositiveClick();
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteEditFragment) {
            NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteEditFragment");
            fragment.onDeleteDialogPositiveClick();
        }
    }

    @Override
    public void onBackPressed() {
        if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteListFragment) {
            NoteListFragment fragment = (NoteListFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteListFragment");
            fragment.onBackPressed();
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteViewFragment) {
            NoteViewFragment fragment = (NoteViewFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteViewFragment");
            fragment.onBackPressed();
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteEditFragment) {
            NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteEditFragment");
            fragment.onBackPressed(null);
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof WelcomeFragment) {
            WelcomeFragment fragment = (WelcomeFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteListFragment");
            fragment.onBackPressed();
        }
    }

    @Override
    public void viewNote(String filename) {
        viewEditNote(filename, false);
    }

    @Override
    public void editNote(String filename) {
        viewEditNote(filename, true);
    }

    // Method used by selecting a existing note from the ListView in NoteViewFragment or NoteEditFragment
    // We need this method in MainActivity because sometimes getSupportFragmentManager() is null
    public void viewEditNote(String filename, boolean isEdit) {
        String currentFilename;

        if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteEditFragment) {
            NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteEditFragment");
            currentFilename = fragment.getFilename();
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteViewFragment) {
            NoteViewFragment fragment = (NoteViewFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteViewFragment");
            currentFilename = fragment.getFilename();
        } else
            currentFilename = "";

        if (!currentFilename.equals(filename)) {
            if (findViewById(R.id.layoutMain).getTag().equals("main-layout-normal"))
                cab.clear();

            if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteEditFragment) {
                NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                        .findFragmentByTag("NoteEditFragment");
                fragment.switchNotes(filename);
            } else {
                Bundle bundle = new Bundle();
                bundle.putString("filename", filename);

                Fragment fragment;
                String tag;

                if (isEdit) {
                    fragment = new NoteEditFragment();
                    tag = "NoteEditFragment";
                } else {
                    fragment = new NoteViewFragment();
                    tag = "NoteViewFragment";
                }

                fragment.setArguments(bundle);

                // Add NoteViewFragment or NoteEditFragment
                getSupportFragmentManager().beginTransaction().replace(R.id.noteViewEdit, fragment, tag)
                        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).commit();
            }
        }
    }

    @Override
    public void onBackDialogNegativeClick(String filename) {
        NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                .findFragmentByTag("NoteEditFragment");
        fragment.onBackDialogNegativeClick(filename);
    }

    @Override
    public void onBackDialogPositiveClick(String filename) {
        NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                .findFragmentByTag("NoteEditFragment");
        fragment.onBackDialogPositiveClick(filename);
    }

    @Override
    public void onSaveDialogNegativeClick() {
        NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                .findFragmentByTag("NoteEditFragment");
        fragment.onSaveDialogNegativeClick();
    }

    @Override
    public void onSaveDialogPositiveClick() {
        NoteEditFragment fragment = (NoteEditFragment) getSupportFragmentManager()
                .findFragmentByTag("NoteEditFragment");
        fragment.onSaveDialogPositiveClick();
    }

    @Override
    public void showBackButtonDialog(String filename) {
        Bundle bundle = new Bundle();
        bundle.putString("filename", filename);

        DialogFragment backFragment = new BackButtonDialogFragment();
        backFragment.setArguments(bundle);
        backFragment.show(getSupportFragmentManager(), "back");
    }

    @Override
    public void showDeleteDialog() {
        showDeleteDialog(true);
    }

    private void showDeleteDialog(boolean clearFilesToDelete) {
        if (clearFilesToDelete)
            filesToDelete = null;

        Bundle bundle = new Bundle();
        bundle.putInt("dialog_title",
                filesToDelete == null || filesToDelete.length == 1 ? R.string.dialog_delete_button_title
                        : R.string.dialog_delete_button_title_plural);

        DialogFragment deleteFragment = new DeleteDialogFragment();
        deleteFragment.setArguments(bundle);
        deleteFragment.show(getSupportFragmentManager(), "delete");
    }

    @Override
    public void showSaveButtonDialog() {
        DialogFragment saveFragment = new SaveButtonDialogFragment();
        saveFragment.show(getSupportFragmentManager(), "save");
    }

    @Override
    public boolean isShareIntent() {
        return false;
    }

    @Override
    public String getCabString(int size) {
        if (size == 1)
            return getResources().getString(R.string.cab_note_selected);
        else
            return getResources().getString(R.string.cab_notes_selected);
    }

    @Override
    public void deleteNotes() {
        filesToDelete = cab.toArray();
        cab.clear();

        showDeleteDialog(false);
    }

    private void reallyDeleteNotes() {
        // Build the pathname to delete each file, them perform delete operation
        for (Object file : filesToDelete) {
            File fileToDelete = new File(getFilesDir() + File.separator + file);
            fileToDelete.delete();
        }

        String[] filesToDelete2 = new String[filesToDelete.length];
        Arrays.asList(filesToDelete).toArray(filesToDelete2);

        // Send broadcasts to update UI
        Intent deleteIntent = new Intent();
        deleteIntent.setAction("com.farmerbb.notepad.DELETE_NOTES");
        deleteIntent.putExtra("files", filesToDelete2);
        LocalBroadcastManager.getInstance(this).sendBroadcast(deleteIntent);

        Intent listIntent = new Intent();
        listIntent.setAction("com.farmerbb.notepad.LIST_NOTES");
        LocalBroadcastManager.getInstance(this).sendBroadcast(listIntent);

        // Show toast notification
        if (filesToDelete.length == 1)
            showToast(R.string.note_deleted);
        else
            showToast(R.string.notes_deleted);

        filesToDelete = null;
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void exportNotes() {
        filesToExport = cab.toArray();
        cab.clear();

        if (filesToExport.length == 1 || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            fileBeingExported = 0;
            reallyExportNotes();
        } else {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);

            try {
                startActivityForResult(intent, EXPORT_TREE);
            } catch (ActivityNotFoundException e) {
                showToast(R.string.error_exporting_notes);
            }
        }
    }

    @Override
    public void exportNote(String filename) {
        filesToExport = new Object[] { filename };
        fileBeingExported = 0;
        reallyExportNotes();
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void reallyExportNotes() {
        String filename = "";

        try {
            filename = loadNoteTitle(filesToExport[fileBeingExported].toString());
        } catch (IOException e) {
            /* Gracefully fail */ }

        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TITLE, generateFilename(filename));

        try {
            startActivityForResult(intent, EXPORT);
        } catch (ActivityNotFoundException e) {
            showToast(R.string.error_exporting_notes);
        }
    }

    private String generateFilename(String filename) {
        // Remove any invalid characters
        final String[] characters = new String[] { "<", ">", ":", "\"", "/", "\\\\", "\\|", "\\?", "\\*" };

        for (String character : characters) {
            filename = filename.replaceAll(character, "");
        }

        // To ensure that the generated filename fits within filesystem limitations,
        // truncate the filename to ~245 characters.
        if (filename.length() > 245)
            filename = filename.substring(0, 245);

        return filename + ".txt";
    }

    // Methods used to generate toast notifications
    private void showToast(int message) {
        Toast toast = Toast.makeText(this, getResources().getString(message), Toast.LENGTH_SHORT);
        toast.show();
    }

    // Loads note from /data/data/com.farmerbb.notepad/files
    public String loadNote(String filename) throws IOException {

        // Initialize StringBuilder which will contain note
        StringBuilder note = new StringBuilder();

        // Open the file on disk
        FileInputStream input = openFileInput(filename);
        InputStreamReader reader = new InputStreamReader(input);
        BufferedReader buffer = new BufferedReader(reader);

        // Load the file
        String line = buffer.readLine();
        while (line != null) {
            note.append(line);
            line = buffer.readLine();
            if (line != null)
                note.append("\n");
        }

        // Close file on disk
        reader.close();

        return (note.toString());
    }

    // Loads first line of a note for display in the ListView
    @Override
    public String loadNoteTitle(String filename) throws IOException {
        // Open the file on disk
        FileInputStream input = openFileInput(filename);
        InputStreamReader reader = new InputStreamReader(input);
        BufferedReader buffer = new BufferedReader(reader);

        // Load the file
        String line = buffer.readLine();

        // Close file on disk
        reader.close();

        return (line);
    }

    // Calculates last modified date/time of a note for display in the ListView
    @Override
    public String loadNoteDate(String filename) {
        Date lastModified = new Date(Long.parseLong(filename));
        return (DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(lastModified));
    }

    @Override
    public void showFab() {
        inCabMode = false;

        if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteListFragment) {
            NoteListFragment fragment = (NoteListFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteListFragment");
            fragment.showFab();
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof WelcomeFragment) {
            WelcomeFragment fragment = (WelcomeFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteListFragment");
            fragment.showFab();
        }
    }

    @Override
    public void hideFab() {
        inCabMode = true;

        if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof NoteListFragment) {
            NoteListFragment fragment = (NoteListFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteListFragment");
            fragment.hideFab();
        } else if (getSupportFragmentManager().findFragmentById(R.id.noteViewEdit) instanceof WelcomeFragment) {
            WelcomeFragment fragment = (WelcomeFragment) getSupportFragmentManager()
                    .findFragmentByTag("NoteListFragment");
            fragment.hideFab();
        }
    }

    @Override
    public void onFirstRunDialogPositiveClick() {
        // Set some initial preferences
        SharedPreferences prefMain = getPreferences(Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefMain.edit();
        editor.putInt("first-run", 1);
        editor.apply();

        SharedPreferences pref = getSharedPreferences(getPackageName() + "_preferences", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor2 = pref.edit();
        editor2.putBoolean("show_dialogs", false);
        editor2.apply();
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {

        if (resultCode == RESULT_OK && resultData != null) {
            successful = true;

            if (requestCode == IMPORT) {
                Uri uri = resultData.getData();
                ClipData clipData = resultData.getClipData();

                if (uri != null)
                    successful = importNote(uri);
                else if (clipData != null)
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        successful = importNote(clipData.getItemAt(i).getUri());
                    }

                // Show toast notification
                showToast(successful
                        ? (uri == null ? R.string.notes_imported_successfully : R.string.note_imported_successfully)
                        : R.string.error_importing_notes);

                // Send broadcast to NoteListFragment to refresh list of notes
                Intent listNotesIntent = new Intent();
                listNotesIntent.setAction("com.farmerbb.notepad.LIST_NOTES");
                LocalBroadcastManager.getInstance(this).sendBroadcast(listNotesIntent);
            } else if (requestCode == EXPORT) {
                try {
                    saveExportedNote(loadNote(filesToExport[fileBeingExported].toString()), resultData.getData());
                } catch (IOException e) {
                    successful = false;
                }

                fileBeingExported++;
                if (fileBeingExported < filesToExport.length)
                    reallyExportNotes();
                else
                    showToast(successful
                            ? (fileBeingExported == 1 ? R.string.note_exported_to : R.string.notes_exported_to)
                            : R.string.error_exporting_notes);

                File fileToDelete = new File(getFilesDir() + File.separator + "exported_note");
                fileToDelete.delete();
            } else if (requestCode == EXPORT_TREE) {
                DocumentFile tree = DocumentFile.fromTreeUri(this, resultData.getData());

                for (Object exportFilename : filesToExport) {
                    try {
                        DocumentFile file = tree.createFile("text/plain",
                                generateFilename(loadNoteTitle(exportFilename.toString())));

                        if (file != null)
                            saveExportedNote(loadNote(exportFilename.toString()), file.getUri());
                        else
                            successful = false;
                    } catch (IOException e) {
                        successful = false;
                    }
                }

                showToast(successful ? R.string.notes_exported_to : R.string.error_exporting_notes);
            }
        }
    }

    private void saveExportedNote(String note, Uri uri) throws IOException {
        // Convert line separators to Windows format
        note = note.replaceAll("\r\n", "\n");
        note = note.replaceAll("\n", "\r\n");

        // Write file to external storage
        OutputStream os = getContentResolver().openOutputStream(uri);
        os.write(note.getBytes());
        os.close();
    }

    private boolean importNote(Uri uri) {
        try {
            File importedFile = new File(getFilesDir(), Long.toString(System.currentTimeMillis()));
            long suffix = 0;

            // Handle cases where a note may have a duplicate title
            while (importedFile.exists()) {
                suffix++;
                importedFile = new File(getFilesDir(), Long.toString(System.currentTimeMillis() + suffix));
            }

            InputStream is = getContentResolver().openInputStream(uri);
            byte[] data = new byte[is.available()];

            if (data.length > 0) {
                OutputStream os = new FileOutputStream(importedFile);
                is.read(data);
                os.write(data);
                is.close();
                os.close();
            }

            return true;
        } catch (IOException e) {
            return false;
        }
    }

    @SuppressLint("SetJavaScriptEnabled")
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void printNote(String contentToPrint) {
        SharedPreferences pref = getSharedPreferences(getPackageName() + "_preferences", MODE_PRIVATE);

        // Create a WebView object specifically for printing
        boolean generateHtml = !(pref.getBoolean("markdown", false)
                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
        WebView webView = generateHtml ? new WebView(this) : new MarkdownView(this);

        // Apply theme
        String theme = pref.getString("theme", "light-sans");
        int textSize = -1;

        String fontFamily = null;

        if (theme.contains("sans")) {
            fontFamily = "sans-serif";
        }

        if (theme.contains("serif")) {
            fontFamily = "serif";
        }

        if (theme.contains("monospace")) {
            fontFamily = "monospace";
        }

        switch (pref.getString("font_size", "normal")) {
        case "smallest":
            textSize = 12;
            break;
        case "small":
            textSize = 14;
            break;
        case "normal":
            textSize = 16;
            break;
        case "large":
            textSize = 18;
            break;
        case "largest":
            textSize = 20;
            break;
        }

        String topBottom = " " + Float.toString(getResources().getDimension(R.dimen.padding_top_bottom_print)
                / getResources().getDisplayMetrics().density) + "px";
        String leftRight = " " + Float.toString(getResources().getDimension(R.dimen.padding_left_right_print)
                / getResources().getDisplayMetrics().density) + "px";
        String fontSize = " " + Integer.toString(textSize) + "px";

        String css = "body { " + "margin:" + topBottom + topBottom + leftRight + leftRight + "; " + "font-family:"
                + fontFamily + "; " + "font-size:" + fontSize + "; " + "}";

        webView.getSettings().setJavaScriptEnabled(false);
        webView.getSettings().setLoadsImagesAutomatically(false);
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(final WebView view, String url) {
                createWebPrintJob(view);
            }
        });

        // Load content into WebView
        if (generateHtml) {
            webView.loadDataWithBaseURL(null,
                    "<link rel='stylesheet' type='text/css' href='data:text/css;base64,"
                            + Base64.encodeToString(css.getBytes(), Base64.DEFAULT) + "' /><html><body><p>"
                            + StringUtils.replace(contentToPrint, "\n", "<br>") + "</p></body></html>",
                    "text/HTML", "UTF-8", null);
        } else
            ((MarkdownView) webView).loadMarkdown(contentToPrint,
                    "data:text/css;base64," + Base64.encodeToString(css.getBytes(), Base64.DEFAULT));
    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void createWebPrintJob(WebView webView) {
        // Get a PrintManager instance
        PrintManager printManager = (PrintManager) getSystemService(PRINT_SERVICE);

        // Get a print adapter instance
        PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();

        // Create a print job with name and adapter instance
        String jobName = getString(R.string.document, getString(R.string.app_name));
        printManager.print(jobName, printAdapter, new PrintAttributes.Builder().build());
    }

    @Override
    public void startMultiSelect() {
        NoteListFragment fragment = null;

        if (findViewById(R.id.layoutMain).getTag().equals("main-layout-normal"))
            fragment = (NoteListFragment) getSupportFragmentManager().findFragmentById(R.id.noteViewEdit);

        if (findViewById(R.id.layoutMain).getTag().equals("main-layout-large"))
            fragment = (NoteListFragment) getSupportFragmentManager().findFragmentById(R.id.noteList);

        if (fragment != null)
            fragment.startMultiSelect();
    }

    @Override
    public SharedPreferences getPreferences(int mode) {
        return getSharedPreferences("MainActivity", mode);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (filesToExport != null && filesToExport.length > 0) {
            ArrayList<String> filesToExportList = new ArrayList<>();
            for (Object file : filesToExport) {
                filesToExportList.add(file.toString());
            }

            outState.putStringArrayList("files_to_export", filesToExportList);
        }

        if (filesToDelete != null && filesToDelete.length > 0) {
            ArrayList<String> filesToDeleteList = new ArrayList<>();
            for (Object file : filesToDelete) {
                filesToDeleteList.add(file.toString());
            }

            outState.putStringArrayList("files_to_delete", filesToDeleteList);
        }

        if (inCabMode && cab.size() > 0)
            outState.putStringArrayList("cab", cab);

        super.onSaveInstanceState(outState);
    }

    @Override
    public ArrayList<String> getCabArray() {
        return cab;
    }
}