Skip to content

Commit

Permalink
First version using Storage Access Framework.
Browse files Browse the repository at this point in the history
Allows the user to select almost any location to store
the dictionaries.
Also update build tools and bump version.
  • Loading branch information
rdoeffinger committed Aug 19, 2021
1 parent e3a0bf0 commit abd7512
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 93 deletions.
4 changes: 2 additions & 2 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hughes.android.dictionary"
android:installLocation="auto"
android:versionCode="113"
android:versionName="5.5.8" >
android:versionCode="114"
android:versionName="5.5.9" >

<uses-feature
android:name="android.hardware.touchscreen"
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.1'
classpath 'com.android.tools.build:gradle:7.0.1'
}
}

Expand Down
1 change: 1 addition & 0 deletions res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
<string name="quickdicDirectoryKey" translatable="false">quickdicDirectory</string>
<string name="quickdicDirectoryTitle">QuickDic directory</string>
<string name="quickdicDirectorySummary">The directory where QuickDic stores dictionaries (empty for default quickDic folder on external storage).</string>
<string name="choose">choose</string>
<string name="wordListFileKey" translatable="false">wordListFile</string>
<string name="wordListFileTitle">Word list file</string>
<string name="wordListFileSummary">The local file where the word list will be appended.</string>
Expand Down
32 changes: 16 additions & 16 deletions res/xml/preferences.xml
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

<ListPreference
<ListPreference
android:key="@string/defaultDicKey"
android:title="@string/defaultDicTitle"
android:summary="@string/defaultDicSummary"
android:persistent="true"
/>

<EditTextPreference
<Preference
android:key="@string/quickdicDirectoryKey"
android:title="@string/quickdicDirectoryTitle"
android:summary="@string/quickdicDirectorySummary"
android:defaultValue=""
android:persistent="true"
/>

<EditTextPreference
android:key="@string/wordListFileKey"

<EditTextPreference
android:key="@string/wordListFileKey"
android:title="@string/wordListFileTitle"
android:summary="@string/wordListFileSummary"
android:defaultValue=""
android:defaultValue=""
android:persistent="true"
/>
<ListPreference
/>

<ListPreference
android:key="@string/fontKey"
android:title="@string/fontTitle"
android:summary="@string/fontSummary"
Expand All @@ -33,7 +33,7 @@
android:entries="@array/fonts"
android:entryValues="@array/fontKeys"
/>

<EditTextPreference
android:key="@string/fontSizeKey"
android:title="@string/fontSizeTitle"
Expand All @@ -42,31 +42,31 @@
android:persistent="true"
/>

<CheckBoxPreference
<CheckBoxPreference
android:key="@string/saveOnlyFirstSubentryKey"
android:title="@string/saveOnlyFirstSubentryTitle"
android:summary="@string/saveOnlyFirstSubentrySummary"
android:defaultValue="false"
android:persistent="true"
/>

<CheckBoxPreference
<CheckBoxPreference
android:key="@string/clickOpensContextMenuKey"
android:title="@string/clickOpensContextMenuTitle"
android:summary="@string/clickOpensContextMenuSummary"
android:defaultValue="false"
android:persistent="true"
/>

<CheckBoxPreference
<CheckBoxPreference
android:key="@string/showPrevNextButtonsKey"
android:title="@string/showPrevNextButtonsTitle"
android:summary="@string/showPrevNextButtonsSummary"
android:defaultValue="true"
android:persistent="true"
/>
<ListPreference

<ListPreference
android:key="@string/themeKey"
android:title="@string/themeTitle"
android:summary="@string/themeSummary"
Expand All @@ -84,4 +84,4 @@
android:persistent="true"
/>

</PreferenceScreen>
</PreferenceScreen>
40 changes: 23 additions & 17 deletions src/com/hughes/android/dictionary/DictionaryActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.provider.DocumentFile;
import android.support.v7.preference.PreferenceManager;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
Expand Down Expand Up @@ -101,6 +102,8 @@
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
Expand All @@ -120,14 +123,15 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public class DictionaryActivity extends AppCompatActivity {

private static final String LOG = "QuickDic";

private DictionaryApplication application;

private File dictFile = null;
private DocumentFile dictFile = null;
private FileChannel dictRaf = null;
private String dictFileTitleName = null;

Expand Down Expand Up @@ -190,7 +194,7 @@ private ListAdapter getListAdapter() {
private MenuItem previousWordMenuItem;

// Never null.
private File wordList = null;
private DocumentFile wordList = null;
private boolean saveOnlyFirstSubentry = false;
private boolean clickOpensContextMenu = false;

Expand All @@ -207,10 +211,10 @@ private ListAdapter getListAdapter() {
public DictionaryActivity() {
}

public static Intent getLaunchIntent(Context c, final File dictFile, final String indexShortName,
public static Intent getLaunchIntent(Context c, final String dictFile, final String indexShortName,
final String searchToken) {
final Intent intent = new Intent(c, DictionaryActivity.class);
intent.putExtra(C.DICT_FILE, dictFile.getPath());
intent.putExtra(C.DICT_FILE, dictFile);
intent.putExtra(C.INDEX_SHORT_NAME, indexShortName);
intent.putExtra(C.SEARCH_TOKEN, searchToken);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
Expand Down Expand Up @@ -437,8 +441,9 @@ public void onCreate(Bundle savedInstanceState) {
for (int i = 0; dictFilename == null && i < dics.size(); ++i) {
try {
Log.d(LOG, "Checking dictionary " + dics.get(i).uncompressedFilename);
final File dictfile = application.getPath(dics.get(i).uncompressedFilename);
Dictionary dic = new Dictionary(new RandomAccessFile(dictfile, "r").getChannel());
final DocumentFile dictfile = application.getPath(dics.get(i).uncompressedFilename);
FileChannel c = getContentResolver().openAssetFileDescriptor(dictfile.getUri(), "r").createInputStream().getChannel();
Dictionary dic = new Dictionary(c);
for (int j = 0; j < dic.indices.size(); ++j) {
Index idx = dic.indices.get(j);
Log.d(LOG, "Checking index " + idx.shortName);
Expand Down Expand Up @@ -471,8 +476,10 @@ public void onCreate(Bundle savedInstanceState) {
finish();
return;
}
if (dictRaf == null)
dictFile = new File(dictFilename);
if (dictRaf == null) {
Uri u = Uri.parse(dictFilename);
dictFile = "content".equals(u.getScheme()) ? DocumentFile.fromSingleUri(getApplicationContext(), u) : DocumentFile.fromFile(new File(u.getPath()));
}

ttsReady = false;
textToSpeech = new TextToSpeech(getApplicationContext(), new OnInitListener() {
Expand All @@ -486,7 +493,7 @@ public void onInit(int status) {
try {
if (dictRaf == null) {
dictFileTitleName = application.getDictionaryName(dictFile.getName());
dictRaf = new RandomAccessFile(dictFile, "r").getChannel();
dictRaf = getContentResolver().openAssetFileDescriptor(dictFile.getUri(), "r").createInputStream().getChannel();
}
this.setTitle("QuickDic: " + dictFileTitleName);
dictionary = new Dictionary(dictRaf);
Expand Down Expand Up @@ -791,12 +798,12 @@ protected void onActivityResult(int requestCode, int resultCode, Intent result)
}
}

private static void setDictionaryPrefs(final Context context, final File dictFile,
private static void setDictionaryPrefs(final Context context, final DocumentFile dictFile,
final String indexShortName) {
final SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(
context).edit();
if (dictFile != null) {
prefs.putString(C.DICT_FILE, dictFile.getPath());
prefs.putString(C.DICT_FILE, dictFile.getUri().toString());
prefs.putString(C.INDEX_SHORT_NAME, indexShortName);
}
prefs.remove(C.SEARCH_TOKEN); // Don't need to save search token.
Expand Down Expand Up @@ -985,7 +992,7 @@ public View getView(int position, View convertView, ViewGroup parent) {
indexInfo, application.languageButtonPixels);
final IntentLauncher intentLauncher = new IntentLauncher(parent.getContext(),
getLaunchIntent(getApplicationContext(),
application.getPath(dictionaryInfo.uncompressedFilename),
application.getPath(dictionaryInfo.uncompressedFilename).getUri().toString(),
indexInfo.shortName, searchView.getQuery().toString())) {
@Override
protected void onGo() {
Expand Down Expand Up @@ -1142,7 +1149,7 @@ public boolean onMenuItemClick(final MenuItem menuItem) {
}
builder.append(dictionaryInfo.dictInfo).append("\n\n");
if (dictFile != null) {
builder.append(getString(R.string.dictionaryPath, dictFile.getPath()))
builder.append(getString(R.string.dictionaryPath, dictFile.getUri().toString()))
.append("\n");
}
builder.append(
Expand Down Expand Up @@ -1372,15 +1379,14 @@ private void onAppendToWordList(final RowBase row) {
Log.d(LOG, "Writing : " + rawText);

try {
wordList.getParentFile().mkdirs();
final PrintWriter out = new PrintWriter(new FileWriter(wordList, true));
final PrintStream out = new PrintStream(getContentResolver().openOutputStream(wordList.getUri(), "wa"));
out.println(rawText);
out.close();
} catch (Exception e) {
Log.e(LOG, "Unable to append to " + wordList.getAbsolutePath(), e);
Log.e(LOG, "Unable to append to " + wordList.getUri().getPath(), e);
if (!isFinishing())
Toast.makeText(this,
getString(R.string.failedAddingToWordList, wordList.getAbsolutePath()),
getString(R.string.failedAddingToWordList, wordList.getUri().getPath()),
Toast.LENGTH_LONG).show();
}
}
Expand Down
60 changes: 35 additions & 25 deletions src/com/hughes/android/dictionary/DictionaryApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.provider.DocumentFile;
import android.support.v7.preference.PreferenceManager;
import android.support.v4.view.MenuItemCompat;
import android.util.Log;
Expand Down Expand Up @@ -263,7 +264,7 @@ private String selectDefaultDir() {
if (!dictDir.isDirectory() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
appContext.getExternalFilesDirs(null);
}
if (efd.isDirectory() && efd.canWrite() && checkFileCreate(efd)) {
if (efd.isDirectory() && efd.canWrite() && checkFileCreate(DocumentFile.fromFile(efd))) {
return efd.getAbsolutePath();
}
}
Expand All @@ -273,40 +274,48 @@ private String selectDefaultDir() {
return dir;
}

public synchronized File getDictDir() {
public synchronized DocumentFile getDictDir() {
// This metaphor doesn't work, because we've already reset
// prefsMightHaveChanged.
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
String dir = prefs.getString(appContext.getString(R.string.quickdicDirectoryKey), "");
if (dir.isEmpty()) {
dir = selectDefaultDir();
}
File dictDir = new File(dir);
dictDir.mkdirs();
DocumentFile dictDir = null;
Uri dirUri = Uri.parse(dir);
if ("content".equals(dirUri.getScheme())) {
dictDir = DocumentFile.fromTreeUri(appContext, dirUri);
} else {
File df = new File(dir);
df.mkdirs();
dictDir = DocumentFile.fromFile(df);
}
if (!dictDir.isDirectory() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
appContext.getExternalFilesDirs(null);
}
return dictDir;
}

public static boolean checkFileCreate(File dir) {
boolean res = false;
File testfile = new File(dir, "quickdic_writetest");
try {
testfile.delete();
res = testfile.createNewFile() & testfile.delete();
} catch (Exception ignored) {
}
return res;
public static boolean checkFileCreate(DocumentFile dir) {
DocumentFile testfile = dir.findFile("quickdic_writetest");
if (testfile != null) testfile.delete();
if (testfile != null && testfile.exists()) return false;
testfile = dir.createFile("", "quickdic_writetest");
if (testfile == null) return false;
return testfile.exists() & testfile.delete();
}

public File getWordListFile() {
public DocumentFile getWordListFile() {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
String file = prefs.getString(appContext.getString(R.string.wordListFileKey), "");
if (file.isEmpty()) {
return new File(getDictDir(), "wordList.txt");
DocumentFile d = getDictDir();
DocumentFile f = d.findFile("wordList.txt");
return f != null ? f : d.createFile("" , "wordList.txt");
}
return new File(file);
Uri u = Uri.parse(file);
return "content".equals(u.getScheme()) ? DocumentFile.fromSingleUri(appContext, u) : DocumentFile.fromFile(new File(u.getPath()));
}

public Theme getSelectedTheme() {
Expand All @@ -325,8 +334,9 @@ public Theme getSelectedTheme() {
}
}

public File getPath(String uncompressedFilename) {
return new File(getDictDir(), uncompressedFilename);
public DocumentFile getPath(String uncompressedFilename) {
DocumentFile res = getDictDir().findFile(uncompressedFilename);
return res != null ? res : DocumentFile.fromFile(new File(uncompressedFilename));
}

String defaultLangISO2 = Locale.getDefault().getLanguage().toLowerCase();
Expand Down Expand Up @@ -442,8 +452,8 @@ public void run() {
}
final DictionaryConfig newDictionaryConfig = new DictionaryConfig();
for (final String uncompressedFilename : oldDictionaryConfig.dictionaryFilesOrdered) {
final File dictFile = getPath(uncompressedFilename);
final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(dictFile);
final DocumentFile dictFile = getPath(uncompressedFilename);
final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(dictFile, appContext.getContentResolver());
if (dictionaryInfo.isValid() || dictFile.exists()) {
newDictionaryConfig.dictionaryFilesOrdered.add(uncompressedFilename);
newDictionaryConfig.uncompressedFilenameToDictionaryInfo.put(
Expand All @@ -455,9 +465,9 @@ public void run() {
// about already?
// Pick them up and put them at the end of the list.
final List<String> toAddSorted = new ArrayList<>();
final File[] dictDirFiles = getDictDir().listFiles();
final DocumentFile[] dictDirFiles = getDictDir().listFiles();
if (dictDirFiles != null) {
for (final File file : dictDirFiles) {
for (final DocumentFile file : dictDirFiles) {
if (file.getName().endsWith(".zip")) {
if (DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO
.containsKey(file.getName().replace(".zip", ""))) {
Expand All @@ -472,17 +482,17 @@ public void run() {
// We have it in our list already.
continue;
}
final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(file);
final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(file, appContext.getContentResolver());
if (!dictionaryInfo.isValid()) {
Log.e(LOG, "Unable to parse dictionary: " + file.getPath());
Log.e(LOG, "Unable to parse dictionary: " + file.getUri().getPath());
}

toAddSorted.add(file.getName());
newDictionaryConfig.uncompressedFilenameToDictionaryInfo.put(
file.getName(), dictionaryInfo);
}
} else {
Log.w(LOG, "dictDir is not a directory: " + getDictDir().getPath());
Log.w(LOG, "dictDir is not a directory: " + getDictDir().getUri().getPath());
}
if (!toAddSorted.isEmpty()) {
Collections.sort(toAddSorted, uncompressedFilenameComparator);
Expand Down
Loading

0 comments on commit abd7512

Please sign in to comment.