From 3636682c29002be4cd1c832345ce11ba4d0851c4 Mon Sep 17 00:00:00 2001 From: Carmen Alvarez Date: Sat, 28 May 2016 15:38:47 +0200 Subject: [PATCH 1/3] Prevent the app from crashing if we couldn't copy the db due to low disk space. --- .../poetassistant/main/MainActivity.java | 40 +++++-- .../main/WarningNoSpaceDialogFragment.java | 97 ++++++++++++++++ .../main/dictionaries/DbUtil.java | 14 ++- .../dictionaries/dictionary/Dictionary.java | 104 ++++++++++------- .../main/dictionaries/rt/Rhymer.java | 79 ++++++++----- .../main/dictionaries/rt/Thesaurus.java | 106 +++++++++++------- app/src/main/res/values/strings.xml | 2 + 7 files changed, 319 insertions(+), 123 deletions(-) create mode 100644 app/src/main/java/ca/rmen/android/poetassistant/main/WarningNoSpaceDialogFragment.java diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java b/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java index 5da1c63b..88d74418 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java @@ -25,8 +25,10 @@ import android.databinding.DataBindingUtil; import android.media.AudioManager; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.support.design.widget.Snackbar; +import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; @@ -38,7 +40,6 @@ import ca.rmen.android.poetassistant.Constants; import ca.rmen.android.poetassistant.R; -import ca.rmen.android.poetassistant.Theme; import ca.rmen.android.poetassistant.about.AboutActivity; import ca.rmen.android.poetassistant.databinding.ActivityMainBinding; import ca.rmen.android.poetassistant.main.dictionaries.Search; @@ -50,9 +51,10 @@ import ca.rmen.android.poetassistant.settings.SettingsActivity; -public class MainActivity extends AppCompatActivity implements OnWordClickedListener { +public class MainActivity extends AppCompatActivity implements OnWordClickedListener, WarningNoSpaceDialogFragment.WarningNoSpaceDialogListener { private static final String TAG = Constants.TAG + MainActivity.class.getSimpleName(); + private static final String DIALOG_TAG = "dialog"; private Search mSearch; private ActivityMainBinding mBinding; @@ -90,14 +92,30 @@ else if (Intent.ACTION_SEND.equals(intent.getAction())) * can already be fast. */ private void loadDictionaries() { - new Thread() { + new AsyncTask() { @Override - public void run() { - Rhymer.getInstance(getApplicationContext()); - Thesaurus.getInstance(getApplicationContext()); - Dictionary.getInstance(getApplicationContext()); + protected Boolean doInBackground(Void... params) { + Rhymer rhymer = Rhymer.getInstance(getApplicationContext()); + rhymer.load(); + Thesaurus thesaurus = Thesaurus.getInstance(getApplicationContext()); + thesaurus.load(); + Dictionary dictionary = Dictionary.getInstance(getApplicationContext()); + dictionary.load(); + return rhymer.isLoaded() && thesaurus.isLoaded() && dictionary.isLoaded(); } - }.start(); + + @Override + protected void onPostExecute(Boolean allDictionariesAreLoaded) { + Fragment warningNoSpaceDialogFragment = getSupportFragmentManager().findFragmentByTag(DIALOG_TAG); + if (!allDictionariesAreLoaded + && warningNoSpaceDialogFragment == null) { + getSupportFragmentManager().beginTransaction().add(new WarningNoSpaceDialogFragment(), DIALOG_TAG).commit(); + } else if (allDictionariesAreLoaded + && warningNoSpaceDialogFragment != null){ + getSupportFragmentManager().beginTransaction().remove(warningNoSpaceDialogFragment).commit(); + } + } + }.execute(); } @Override @@ -172,6 +190,12 @@ public void onWordClicked(String word, Tab tab) { mSearch.search(word, tab); } + @Override + public void onWarningNoSpaceDialogDismissed() { + Log.v(TAG, "onWarningNoSpaceDialogDismissed"); + finish(); + } + // Hide the keyboard when we navigate to any tab other than the reader tab. private final ViewPager.OnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() { @Override diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/WarningNoSpaceDialogFragment.java b/app/src/main/java/ca/rmen/android/poetassistant/main/WarningNoSpaceDialogFragment.java new file mode 100644 index 00000000..0580f657 --- /dev/null +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/WarningNoSpaceDialogFragment.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016 Carmen Alvarez + * + * This file is part of Poet Assistant. + * + * Poet Assistant is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Poet Assistant is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Poet Assistant. If not, see . + */ + +package ca.rmen.android.poetassistant.main; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.Fragment; +import android.support.v7.app.AlertDialog; +import android.util.Log; + +import ca.rmen.android.poetassistant.Constants; +import ca.rmen.android.poetassistant.R; + + +/** + * Shows a dialog with a title, message, and ok button. + * The activity or fragment which adds this dialog should implement the + * WarningDialogListener interface. + */ +public class WarningNoSpaceDialogFragment extends DialogFragment { + + private static final String TAG = Constants.TAG + WarningNoSpaceDialogFragment.class.getSimpleName(); + + public interface WarningNoSpaceDialogListener { + void onWarningNoSpaceDialogDismissed(); + } + + /** + * @return a Dialog with a title, message and ok button. + */ + @Override + @NonNull + public Dialog onCreateDialog(Bundle savedInstanceState) { + Log.v(TAG, "onCreateDialog: savedInstanceState = " + savedInstanceState); + Context context = getActivity(); + + OnClickListener positiveListener = new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + notifyListener(); + } + }; + + DialogInterface.OnDismissListener dismissListener = new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + notifyListener(); + } + }; + + Dialog dialog = new AlertDialog.Builder(context) + .setTitle(context.getString(R.string.warning_no_space_title)) + .setMessage(context.getString(R.string.warning_no_space_message)) + .setPositiveButton(android.R.string.ok, positiveListener) + .setOnDismissListener(dismissListener) + .create(); + dialog.setOnDismissListener(dismissListener); + return dialog; + } + + private void notifyListener() { + Fragment parentFragment = getParentFragment(); + if (parentFragment instanceof WarningNoSpaceDialogListener) { + ((WarningNoSpaceDialogListener) parentFragment).onWarningNoSpaceDialogDismissed(); + } else if (getActivity() instanceof WarningNoSpaceDialogListener) { + ((WarningNoSpaceDialogListener) getActivity()).onWarningNoSpaceDialogDismissed(); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + notifyListener(); + } +} diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbUtil.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbUtil.java index 197f41ae..4f5759f3 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbUtil.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbUtil.java @@ -21,6 +21,8 @@ import android.content.Context; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.support.annotation.Nullable; import android.util.Log; import java.io.File; @@ -36,11 +38,20 @@ public class DbUtil { private DbUtil() { } + /** + * @return null if the database could not be opened + */ + @Nullable public static SQLiteDatabase open(Context context, String dbName, int version) { DbUtil.copyDb(context, dbName, version); String dbFile = getDbFileName(dbName, version); File dbPath = new File(context.getDir("databases", Context.MODE_PRIVATE), dbFile); - return SQLiteDatabase.openDatabase(dbPath.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); + try { + return SQLiteDatabase.openDatabase(dbPath.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); + } catch (SQLiteException e) { + Log.w(TAG, "Could not open database " + dbName + ":" + version + ": " + e.getMessage(), e); + return null; + } } private static void copyDb(Context context, String dbName, int version) { @@ -63,6 +74,7 @@ private static void copyDb(Context context, String dbName, int version) { } } catch (IOException e) { Log.e(TAG, "Error writing to " + dbPath + ": " + e.getMessage(), e); + deleteDb(context, dbName, version); } Log.v(TAG, "wrote " + dbPath); } diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java index a1e273d4..50bfc2c4 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java @@ -22,6 +22,8 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.TextUtils; import ca.rmen.android.poetassistant.main.dictionaries.DbUtil; @@ -33,7 +35,8 @@ public class Dictionary { private static Dictionary sInstance; - private final SQLiteDatabase mDb; + private final Context mContext; + private SQLiteDatabase mDb; public static synchronized Dictionary getInstance(Context context) { if (sInstance == null) sInstance = new Dictionary(context); @@ -41,59 +44,78 @@ public static synchronized Dictionary getInstance(Context context) { } private Dictionary(Context context) { - mDb = DbUtil.open(context, DB_FILE, DB_VERSION); + mContext = context; } + public void load() { + if (mDb == null) { + mDb = DbUtil.open(mContext, DB_FILE, DB_VERSION); + } + } + + public boolean isLoaded() { + return mDb != null; + } + + @NonNull public DictionaryEntry lookup(String word) { - String[] projection = new String[]{"part_of_speech", "definition"}; - String selection = "word=?"; - String[] selectionArgs = new String[]{word}; - String lookupWord = word; - Cursor cursor = mDb.query("dictionary", projection, selection, selectionArgs, null, null, null); - - if (cursor != null && cursor.getCount() == 0) { - String closestWord = new WordSimilarities().findClosestWord(word, mDb, "stems", "word", "stem"); - if (closestWord != null) { - lookupWord = closestWord; - cursor.close(); - selectionArgs = new String[]{lookupWord}; - cursor = mDb.query("dictionary", projection, selection, selectionArgs, null, null, null); + load(); + if (mDb != null) { + + String[] projection = new String[]{"part_of_speech", "definition"}; + String selection = "word=?"; + String[] selectionArgs = new String[]{word}; + String lookupWord = word; + Cursor cursor = mDb.query("dictionary", projection, selection, selectionArgs, null, null, null); + + if (cursor != null && cursor.getCount() == 0) { + String closestWord = new WordSimilarities().findClosestWord(word, mDb, "stems", "word", "stem"); + if (closestWord != null) { + lookupWord = closestWord; + cursor.close(); + selectionArgs = new String[]{lookupWord}; + cursor = mDb.query("dictionary", projection, selection, selectionArgs, null, null, null); + } } - } - if (cursor != null) { - DictionaryEntry.DictionaryEntryDetails[] result = new DictionaryEntry.DictionaryEntryDetails[cursor.getCount()]; - try { - while (cursor.moveToNext()) { - String partOfSpeech = cursor.getString(0); - String definition = cursor.getString(1); - result[cursor.getPosition()] = new DictionaryEntry.DictionaryEntryDetails(partOfSpeech, definition); + if (cursor != null) { + DictionaryEntry.DictionaryEntryDetails[] result = new DictionaryEntry.DictionaryEntryDetails[cursor.getCount()]; + try { + while (cursor.moveToNext()) { + String partOfSpeech = cursor.getString(0); + String definition = cursor.getString(1); + result[cursor.getPosition()] = new DictionaryEntry.DictionaryEntryDetails(partOfSpeech, definition); + } + return new DictionaryEntry(lookupWord, result); + } finally { + cursor.close(); } - return new DictionaryEntry(lookupWord, result); - } finally { - cursor.close(); } } return new DictionaryEntry(word, new DictionaryEntry.DictionaryEntryDetails[0]); } + @Nullable public DictionaryEntry getRandomEntry() { - String[] projection = new String[]{"word"}; - String orderBy = "RANDOM()"; - String limit = "1"; - Cursor cursor = mDb.query(false, "dictionary", projection, null, null, null, null, - orderBy, limit); - if (cursor != null) { - String word = null; - try { - if (cursor.moveToNext()) { - word = cursor.getString(0); + load(); + if (mDb != null) { + String[] projection = new String[]{"word"}; + String orderBy = "RANDOM()"; + String limit = "1"; + Cursor cursor = mDb.query(false, "dictionary", projection, null, null, null, null, + orderBy, limit); + if (cursor != null) { + String word = null; + try { + if (cursor.moveToNext()) { + word = cursor.getString(0); + } + } finally { + cursor.close(); } - } finally { - cursor.close(); - } - if (TextUtils.isEmpty(word)) return null; - return lookup(word); + if (TextUtils.isEmpty(word)) return null; + return lookup(word); + } } return null; diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java index 37203f92..6c884cad 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java @@ -22,6 +22,7 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.Collections; @@ -38,7 +39,8 @@ public class Rhymer extends ca.rmen.rhymer.Rhymer { private static final String DB_FILE = "rhymes"; private static final int DB_VERSION = 2; - private final SQLiteDatabase mDb; + private final Context mContext; + private SQLiteDatabase mDb; private static Rhymer sInstance = null; @@ -48,30 +50,43 @@ public static synchronized Rhymer getInstance(Context context) { } private Rhymer(Context context) { - mDb = DbUtil.open(context, DB_FILE, DB_VERSION); + mContext = context; } + public void load() { + if (mDb == null) { + mDb = DbUtil.open(mContext, DB_FILE, DB_VERSION); + } + } + public boolean isLoaded() { + return mDb != null; + } + + @NonNull @Override protected List getWordVariants(String word) { - String[] projection = new String[]{"variant_number", "stress_syllables", "last_syllable", "last_two_syllables", "last_three_syllables"}; - String selection = "word=?"; - String[] selectionArgs = new String[]{word}; - Cursor cursor = mDb.query("word_variants", projection, selection, selectionArgs, null, null, null); List result = new ArrayList<>(); - if (cursor != null) { - try { - while (cursor.moveToNext()) { - int column = 0; - int variantNumber = cursor.getInt(column++); - String lastStressSyllable = cursor.getString(column++); - String lastSyllable = cursor.getString(column++); - String lastTwoSyllables = cursor.getString(column++); - String lastThreeSyllables = cursor.getString(column); - WordVariant wordVariant = new WordVariant(variantNumber, lastStressSyllable, lastSyllable, lastTwoSyllables, lastThreeSyllables); - result.add(wordVariant); + load(); + if (mDb != null) { + String[] projection = new String[]{"variant_number", "stress_syllables", "last_syllable", "last_two_syllables", "last_three_syllables"}; + String selection = "word=?"; + String[] selectionArgs = new String[]{word}; + Cursor cursor = mDb.query("word_variants", projection, selection, selectionArgs, null, null, null); + if (cursor != null) { + try { + while (cursor.moveToNext()) { + int column = 0; + int variantNumber = cursor.getInt(column++); + String lastStressSyllable = cursor.getString(column++); + String lastSyllable = cursor.getString(column++); + String lastTwoSyllables = cursor.getString(column++); + String lastThreeSyllables = cursor.getString(column); + WordVariant wordVariant = new WordVariant(variantNumber, lastStressSyllable, lastSyllable, lastTwoSyllables, lastThreeSyllables); + result.add(wordVariant); + } + } finally { + cursor.close(); } - } finally { - cursor.close(); } } return result; @@ -114,20 +129,24 @@ protected SortedSet getWordsWithLastThreeSyllables(String syllables) { return lookupBySyllable(syllables, "last_three_syllables"); } + @NonNull private SortedSet lookupBySyllable(String syllables, String columnName) { - String[] projection = new String[]{"word"}; - String selection = columnName + "=?"; - String[] selectionArgs = new String[]{syllables}; - Cursor cursor = mDb.query("word_variants", projection, selection, selectionArgs, null, null, null); SortedSet result = new TreeSet<>(); - if (cursor != null) { - try { - while (cursor.moveToNext()) { - String word = cursor.getString(0); - result.add(word); + load(); + if (mDb != null) { + String[] projection = new String[]{"word"}; + String selection = columnName + "=?"; + String[] selectionArgs = new String[]{syllables}; + Cursor cursor = mDb.query("word_variants", projection, selection, selectionArgs, null, null, null); + if (cursor != null) { + try { + while (cursor.moveToNext()) { + String word = cursor.getString(0); + result.add(word); + } + } finally { + cursor.close(); } - } finally { - cursor.close(); } } return result; diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java index e0c5e8e8..c4141c0a 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java @@ -22,6 +22,7 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; import android.text.TextUtils; import java.util.Collections; @@ -37,7 +38,8 @@ public class Thesaurus { private static Thesaurus sInstance; - private final SQLiteDatabase mDb; + private final Context mContext; + private SQLiteDatabase mDb; public static synchronized Thesaurus getInstance(Context context) { @@ -46,41 +48,55 @@ public static synchronized Thesaurus getInstance(Context context) { } private Thesaurus(Context context) { - mDb = DbUtil.open(context, DB_FILE, DB_VERSION); + mContext = context; } + public void load() { + if (mDb == null) { + mDb = DbUtil.open(mContext, DB_FILE, DB_VERSION); + } + } + + public boolean isLoaded() { + return mDb != null; + } + + @NonNull public ThesaurusEntry lookup(String word) { - String[] projection = new String[]{"word_type", "synonyms", "antonyms"}; - String selection = "word=?"; - String[] selectionArgs = new String[]{word}; - String lookupWord = word; - Cursor cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); - - - if (cursor != null && cursor.getCount() == 0) { - String closestWord = new WordSimilarities().findClosestWord(word, mDb, "thesaurus", "word", "stem"); - if (closestWord != null) { - lookupWord = closestWord; - cursor.close(); - selectionArgs = new String[]{lookupWord}; - cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); + load(); + if (mDb != null) { + String[] projection = new String[]{"word_type", "synonyms", "antonyms"}; + String selection = "word=?"; + String[] selectionArgs = new String[]{word}; + String lookupWord = word; + Cursor cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); + + + if (cursor != null && cursor.getCount() == 0) { + String closestWord = new WordSimilarities().findClosestWord(word, mDb, "thesaurus", "word", "stem"); + if (closestWord != null) { + lookupWord = closestWord; + cursor.close(); + selectionArgs = new String[]{lookupWord}; + cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); + } } - } - if (cursor != null) { - ThesaurusEntry.ThesaurusEntryDetails[] result = new ThesaurusEntry.ThesaurusEntryDetails[cursor.getCount()]; - try { - while (cursor.moveToNext()) { - ThesaurusEntry.WordType wordType = ThesaurusEntry.WordType.valueOf(cursor.getString(0)); - String synonymsList = cursor.getString(1); - String antonymsList = cursor.getString(2); - String[] synonyms = split(synonymsList); - String[] antonyms = split(antonymsList); - result[cursor.getPosition()] = new ThesaurusEntry.ThesaurusEntryDetails(wordType, synonyms, antonyms); + if (cursor != null) { + ThesaurusEntry.ThesaurusEntryDetails[] result = new ThesaurusEntry.ThesaurusEntryDetails[cursor.getCount()]; + try { + while (cursor.moveToNext()) { + ThesaurusEntry.WordType wordType = ThesaurusEntry.WordType.valueOf(cursor.getString(0)); + String synonymsList = cursor.getString(1); + String antonymsList = cursor.getString(2); + String[] synonyms = split(synonymsList); + String[] antonyms = split(antonymsList); + result[cursor.getPosition()] = new ThesaurusEntry.ThesaurusEntryDetails(wordType, synonyms, antonyms); + } + return new ThesaurusEntry(lookupWord, result); + } finally { + cursor.close(); } - return new ThesaurusEntry(lookupWord, result); - } finally { - cursor.close(); } } return new ThesaurusEntry(word, new ThesaurusEntry.ThesaurusEntryDetails[0]); @@ -89,22 +105,26 @@ public ThesaurusEntry lookup(String word) { /** * @return the synonyms of the given word, in any order. */ + @NonNull public Set getFlatSynonyms(String word) { Set flatSynonyms = new HashSet<>(); - - String[] projection = new String[]{"synonyms"}; - String selection = "word=?"; - String[] selectionArgs = new String[]{word}; - Cursor cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); - if (cursor != null) { - try { - while (cursor.moveToNext()) { - String synonymsList = cursor.getString(0); - String[] synonyms = split(synonymsList); - Collections.addAll(flatSynonyms, synonyms); + load(); + if (mDb != null) { + + String[] projection = new String[]{"synonyms"}; + String selection = "word=?"; + String[] selectionArgs = new String[]{word}; + Cursor cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); + if (cursor != null) { + try { + while (cursor.moveToNext()) { + String synonymsList = cursor.getString(0); + String[] synonyms = split(synonymsList); + Collections.addAll(flatSynonyms, synonyms); + } + } finally { + cursor.close(); } - } finally { - cursor.close(); } } return flatSynonyms; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d13f13d9..d5abd931 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,6 +84,8 @@ "\n %s\n" " %s\n" \n%1$s. %2$s + Insufficient storage space + Your device doesn\'t have enough storage space to use Poet Assistant. Try to free up some space. Theme From faa236f9fe3aa47a63a34a31332856ec34c5a561 Mon Sep 17 00:00:00 2001 From: Carmen Alvarez Date: Sat, 28 May 2016 18:55:28 +0200 Subject: [PATCH 2/3] Prevent loading the db multiple times in concurrent threads. --- .../poetassistant/main/MainActivity.java | 3 - .../{DbUtil.java => DbHelper.java} | 79 +++++++++++-------- .../dictionaries/dictionary/Dictionary.java | 33 +++----- .../main/dictionaries/rt/Rhymer.java | 26 +++--- .../main/dictionaries/rt/Thesaurus.java | 33 +++----- 5 files changed, 81 insertions(+), 93 deletions(-) rename app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/{DbUtil.java => DbHelper.java} (50%) diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java b/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java index 88d74418..38373aca 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/MainActivity.java @@ -96,11 +96,8 @@ private void loadDictionaries() { @Override protected Boolean doInBackground(Void... params) { Rhymer rhymer = Rhymer.getInstance(getApplicationContext()); - rhymer.load(); Thesaurus thesaurus = Thesaurus.getInstance(getApplicationContext()); - thesaurus.load(); Dictionary dictionary = Dictionary.getInstance(getApplicationContext()); - dictionary.load(); return rhymer.isLoaded() && thesaurus.isLoaded() && dictionary.isLoaded(); } diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbUtil.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbHelper.java similarity index 50% rename from app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbUtil.java rename to app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbHelper.java index 4f5759f3..f4773a13 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbUtil.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/DbHelper.java @@ -22,7 +22,6 @@ import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; -import android.support.annotation.Nullable; import android.util.Log; import java.io.File; @@ -32,39 +31,53 @@ import ca.rmen.android.poetassistant.Constants; -public class DbUtil { - private static final String TAG = Constants.TAG + DbUtil.class.getSimpleName(); +public class DbHelper { + private static final String TAG = Constants.TAG + DbHelper.class.getSimpleName(); - private DbUtil() { + private final Context mContext; + private final String mDbName; + private final int mVersion; + private SQLiteDatabase mDb; + private final Object mLock = new Object(); + + public DbHelper(Context context, String dbName, int version) { + mContext = context; + mDbName = dbName; + mVersion = version; + } + + public SQLiteDatabase getDb() { + open(); + return mDb; } - /** - * @return null if the database could not be opened - */ - @Nullable - public static SQLiteDatabase open(Context context, String dbName, int version) { - DbUtil.copyDb(context, dbName, version); - String dbFile = getDbFileName(dbName, version); - File dbPath = new File(context.getDir("databases", Context.MODE_PRIVATE), dbFile); - try { - return SQLiteDatabase.openDatabase(dbPath.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); - } catch (SQLiteException e) { - Log.w(TAG, "Could not open database " + dbName + ":" + version + ": " + e.getMessage(), e); - return null; + private void open() { + synchronized (mLock) { + if (mDb == null) { + Log.v(TAG, "Open db " + mDbName + ":" + mVersion); + copyDb(); + String dbFile = getDbFileName(mVersion); + File dbPath = new File(mContext.getDir("databases", Context.MODE_PRIVATE), dbFile); + try { + mDb = SQLiteDatabase.openDatabase(dbPath.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); + } catch (SQLiteException e) { + Log.w(TAG, "Could not open database " + mDbName + ":" + mVersion + ": " + e.getMessage(), e); + } + } } } - private static void copyDb(Context context, String dbName, int version) { - String dbFileName = getDbFileName(dbName, version); - File dbPath = getDbFile(context, dbFileName); + private void copyDb() { + String dbFileName = getDbFileName(mVersion); + File dbPath = getDbFile(dbFileName); if (!dbPath.exists()) { Log.v(TAG, dbPath + " not found"); - for (int i = 0; i < version; i++) { - deleteDb(context, dbName, i); + for (int i = 0; i < mVersion; i++) { + deleteDb(i); } try { - InputStream is = context.getAssets().open(dbFileName); + InputStream is = mContext.getAssets().open(dbFileName); FileOutputStream os = new FileOutputStream(dbPath); byte[] buffer = new byte[1024]; int read = is.read(buffer); @@ -72,30 +85,30 @@ private static void copyDb(Context context, String dbName, int version) { os.write(buffer, 0, read); read = is.read(buffer); } + Log.v(TAG, "wrote " + dbPath); } catch (IOException e) { Log.e(TAG, "Error writing to " + dbPath + ": " + e.getMessage(), e); - deleteDb(context, dbName, version); + deleteDb(mVersion); } - Log.v(TAG, "wrote " + dbPath); } } - private static String getDbFileName(String dbName, int version) { - if (version == 1) return dbName + ".db"; - return dbName + version + ".db"; + private String getDbFileName(int version) { + if (version == 1) return mDbName + ".db"; + return mDbName + version + ".db"; } - private static void deleteDb(Context context, String dbName, int version) { - String dbFileName = getDbFileName(dbName, version); - File dbPath = getDbFile(context, dbFileName); + private void deleteDb(int version) { + String dbFileName = getDbFileName(version); + File dbPath = getDbFile(dbFileName); if (dbPath.exists()) { boolean deleted = dbPath.delete(); Log.v(TAG, "dbDelete: deletion of " + dbPath.getAbsolutePath() + ": " + deleted); } } - private static File getDbFile(Context context, String filename) { - File dbDir = context.getDir("databases", Context.MODE_PRIVATE); + private File getDbFile(String filename) { + File dbDir = mContext.getDir("databases", Context.MODE_PRIVATE); return new File(dbDir, filename); } diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java index 50bfc2c4..d8e131b2 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/dictionary/Dictionary.java @@ -26,7 +26,7 @@ import android.support.annotation.Nullable; import android.text.TextUtils; -import ca.rmen.android.poetassistant.main.dictionaries.DbUtil; +import ca.rmen.android.poetassistant.main.dictionaries.DbHelper; import ca.rmen.android.poetassistant.main.dictionaries.textprocessing.WordSimilarities; public class Dictionary { @@ -35,46 +35,39 @@ public class Dictionary { private static Dictionary sInstance; - private final Context mContext; - private SQLiteDatabase mDb; + private final DbHelper mDbHelper; public static synchronized Dictionary getInstance(Context context) { if (sInstance == null) sInstance = new Dictionary(context); return sInstance; } - private Dictionary(Context context) { - mContext = context; - } - - public void load() { - if (mDb == null) { - mDb = DbUtil.open(mContext, DB_FILE, DB_VERSION); - } + private Dictionary (Context context) { + mDbHelper = new DbHelper(context, DB_FILE, DB_VERSION); } public boolean isLoaded() { - return mDb != null; + return mDbHelper.getDb() != null; } @NonNull public DictionaryEntry lookup(String word) { - load(); - if (mDb != null) { + SQLiteDatabase db = mDbHelper.getDb(); + if (db != null) { String[] projection = new String[]{"part_of_speech", "definition"}; String selection = "word=?"; String[] selectionArgs = new String[]{word}; String lookupWord = word; - Cursor cursor = mDb.query("dictionary", projection, selection, selectionArgs, null, null, null); + Cursor cursor = db.query("dictionary", projection, selection, selectionArgs, null, null, null); if (cursor != null && cursor.getCount() == 0) { - String closestWord = new WordSimilarities().findClosestWord(word, mDb, "stems", "word", "stem"); + String closestWord = new WordSimilarities().findClosestWord(word, db, "stems", "word", "stem"); if (closestWord != null) { lookupWord = closestWord; cursor.close(); selectionArgs = new String[]{lookupWord}; - cursor = mDb.query("dictionary", projection, selection, selectionArgs, null, null, null); + cursor = db.query("dictionary", projection, selection, selectionArgs, null, null, null); } } if (cursor != null) { @@ -96,12 +89,12 @@ public DictionaryEntry lookup(String word) { @Nullable public DictionaryEntry getRandomEntry() { - load(); - if (mDb != null) { + SQLiteDatabase db = mDbHelper.getDb(); + if (db != null) { String[] projection = new String[]{"word"}; String orderBy = "RANDOM()"; String limit = "1"; - Cursor cursor = mDb.query(false, "dictionary", projection, null, null, null, null, + Cursor cursor = db.query(false, "dictionary", projection, null, null, null, null, orderBy, limit); if (cursor != null) { String word = null; diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java index 6c884cad..7d87fd1f 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Rhymer.java @@ -32,15 +32,14 @@ import java.util.SortedSet; import java.util.TreeSet; -import ca.rmen.android.poetassistant.main.dictionaries.DbUtil; +import ca.rmen.android.poetassistant.main.dictionaries.DbHelper; import ca.rmen.rhymer.RhymeResult; import ca.rmen.rhymer.WordVariant; public class Rhymer extends ca.rmen.rhymer.Rhymer { private static final String DB_FILE = "rhymes"; private static final int DB_VERSION = 2; - private final Context mContext; - private SQLiteDatabase mDb; + private final DbHelper mDbHelper; private static Rhymer sInstance = null; @@ -50,28 +49,23 @@ public static synchronized Rhymer getInstance(Context context) { } private Rhymer(Context context) { - mContext = context; + mDbHelper = new DbHelper(context, DB_FILE, DB_VERSION); } - public void load() { - if (mDb == null) { - mDb = DbUtil.open(mContext, DB_FILE, DB_VERSION); - } - } public boolean isLoaded() { - return mDb != null; + return mDbHelper.getDb() != null; } @NonNull @Override protected List getWordVariants(String word) { List result = new ArrayList<>(); - load(); - if (mDb != null) { + SQLiteDatabase db = mDbHelper.getDb(); + if (db != null) { String[] projection = new String[]{"variant_number", "stress_syllables", "last_syllable", "last_two_syllables", "last_three_syllables"}; String selection = "word=?"; String[] selectionArgs = new String[]{word}; - Cursor cursor = mDb.query("word_variants", projection, selection, selectionArgs, null, null, null); + Cursor cursor = db.query("word_variants", projection, selection, selectionArgs, null, null, null); if (cursor != null) { try { while (cursor.moveToNext()) { @@ -132,12 +126,12 @@ protected SortedSet getWordsWithLastThreeSyllables(String syllables) { @NonNull private SortedSet lookupBySyllable(String syllables, String columnName) { SortedSet result = new TreeSet<>(); - load(); - if (mDb != null) { + SQLiteDatabase db = mDbHelper.getDb(); + if (db != null) { String[] projection = new String[]{"word"}; String selection = columnName + "=?"; String[] selectionArgs = new String[]{syllables}; - Cursor cursor = mDb.query("word_variants", projection, selection, selectionArgs, null, null, null); + Cursor cursor = db.query("word_variants", projection, selection, selectionArgs, null, null, null); if (cursor != null) { try { while (cursor.moveToNext()) { diff --git a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java index c4141c0a..ebe5e76a 100644 --- a/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java +++ b/app/src/main/java/ca/rmen/android/poetassistant/main/dictionaries/rt/Thesaurus.java @@ -29,7 +29,7 @@ import java.util.HashSet; import java.util.Set; -import ca.rmen.android.poetassistant.main.dictionaries.DbUtil; +import ca.rmen.android.poetassistant.main.dictionaries.DbHelper; import ca.rmen.android.poetassistant.main.dictionaries.textprocessing.WordSimilarities; public class Thesaurus { @@ -37,10 +37,7 @@ public class Thesaurus { private static final int DB_VERSION = 2; private static Thesaurus sInstance; - - private final Context mContext; - private SQLiteDatabase mDb; - + private final DbHelper mDbHelper; public static synchronized Thesaurus getInstance(Context context) { if (sInstance == null) sInstance = new Thesaurus(context); @@ -48,37 +45,31 @@ public static synchronized Thesaurus getInstance(Context context) { } private Thesaurus(Context context) { - mContext = context; - } - - public void load() { - if (mDb == null) { - mDb = DbUtil.open(mContext, DB_FILE, DB_VERSION); - } + mDbHelper = new DbHelper(context, DB_FILE, DB_VERSION); } public boolean isLoaded() { - return mDb != null; + return mDbHelper.getDb() != null; } @NonNull public ThesaurusEntry lookup(String word) { - load(); - if (mDb != null) { + SQLiteDatabase db = mDbHelper.getDb(); + if (db != null) { String[] projection = new String[]{"word_type", "synonyms", "antonyms"}; String selection = "word=?"; String[] selectionArgs = new String[]{word}; String lookupWord = word; - Cursor cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); + Cursor cursor = db.query("thesaurus", projection, selection, selectionArgs, null, null, null); if (cursor != null && cursor.getCount() == 0) { - String closestWord = new WordSimilarities().findClosestWord(word, mDb, "thesaurus", "word", "stem"); + String closestWord = new WordSimilarities().findClosestWord(word, db, "thesaurus", "word", "stem"); if (closestWord != null) { lookupWord = closestWord; cursor.close(); selectionArgs = new String[]{lookupWord}; - cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); + cursor = db.query("thesaurus", projection, selection, selectionArgs, null, null, null); } } @@ -108,13 +99,13 @@ public ThesaurusEntry lookup(String word) { @NonNull public Set getFlatSynonyms(String word) { Set flatSynonyms = new HashSet<>(); - load(); - if (mDb != null) { + SQLiteDatabase db = mDbHelper.getDb(); + if (db != null) { String[] projection = new String[]{"synonyms"}; String selection = "word=?"; String[] selectionArgs = new String[]{word}; - Cursor cursor = mDb.query("thesaurus", projection, selection, selectionArgs, null, null, null); + Cursor cursor = db.query("thesaurus", projection, selection, selectionArgs, null, null, null); if (cursor != null) { try { while (cursor.moveToNext()) { From d83b32e1c4e54447fda1a5b1034e827178f667c8 Mon Sep 17 00:00:00 2001 From: Carmen Alvarez Date: Sat, 28 May 2016 19:26:59 +0200 Subject: [PATCH 3/3] New version 1.6.5 --- CHANGELOG.md | 5 +++++ app/build.gradle | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16530692..1d862107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Change Log ========== +1.6.5 *(2016-05-28)* +-------------------- + +* Prevent a crash if the user does not have enough disk space. + 1.6.4 *(2016-05-18)* -------------------- diff --git a/app/build.gradle b/app/build.gradle index 5304972c..2002e70e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,8 +31,8 @@ android { applicationId "ca.rmen.android.poetassistant" minSdkVersion 16 targetSdkVersion 23 - versionCode 164 - versionName "1.6.4" + versionCode 165 + versionName "1.6.5" vectorDrawables.useSupportLibrary = true } buildTypes {