diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 152a19e3b..cbbaf399b 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,7 +19,6 @@
-
@@ -36,7 +35,6 @@
android:label="@string/app_name"
android:largeHeap="true"
android:networkSecurityConfig="@xml/network_security_config"
- android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/AppTheme">
diff --git a/app/src/main/java/com/hippo/ehviewer/AppConfig.java b/app/src/main/java/com/hippo/ehviewer/AppConfig.java
index 8eb341fe3..698da29d4 100644
--- a/app/src/main/java/com/hippo/ehviewer/AppConfig.java
+++ b/app/src/main/java/com/hippo/ehviewer/AppConfig.java
@@ -53,7 +53,16 @@ public class AppConfig {
@Nullable
public static File getExternalAppDir() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
- File dir = new File(Environment.getExternalStorageDirectory(), APP_DIRNAME);
+ File dir = sContext.getExternalFilesDir(null);
+ return FileUtils.ensureDirectory(dir) ? dir : null;
+ }
+ return null;
+ }
+
+ @Nullable
+ public static File getExternalMediaDir() {
+ if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
+ File dir = new File(sContext.getExternalMediaDirs()[0], APP_DIRNAME);
return FileUtils.ensureDirectory(dir) ? dir : null;
}
return null;
@@ -64,6 +73,7 @@ public class AppConfig {
*/
@Nullable
public static File getDirInExternalAppDir(String filename) {
+
File appFolder = getExternalAppDir();
if (appFolder != null) {
File dir = new File(appFolder, filename);
@@ -94,7 +104,7 @@ public class AppConfig {
@Nullable
public static File getExternalImageDir() {
- return getDirInExternalAppDir(IMAGE);
+ return getExternalMediaDir();
}
@Nullable
@@ -102,11 +112,6 @@ public class AppConfig {
return getDirInExternalAppDir(PARSE_ERROR);
}
- @Nullable
- public static File getExternalLogcatDir() {
- return getDirInExternalAppDir(LOGCAT);
- }
-
@Nullable
public static File getExternalDataDir() {
return getDirInExternalAppDir(DATA);
diff --git a/app/src/main/java/com/hippo/ehviewer/EhDB.java b/app/src/main/java/com/hippo/ehviewer/EhDB.java
index f6584a723..85e66d286 100644
--- a/app/src/main/java/com/hippo/ehviewer/EhDB.java
+++ b/app/src/main/java/com/hippo/ehviewer/EhDB.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -619,7 +620,7 @@ public class EhDB {
return true;
}
- public static synchronized boolean exportDB(Context context, File file) {
+ public static synchronized boolean exportDB(Context context, Uri uri) {
final String ehExportName = "eh.export.db";
// Delete old export db
@@ -659,7 +660,7 @@ public class EhDB {
OutputStream os = null;
try {
is = new FileInputStream(dbFile);
- os = new FileOutputStream(file);
+ os = context.getContentResolver().openOutputStream(uri);;
IOUtils.copy(is, os);
return true;
} catch (IOException e) {
@@ -669,7 +670,6 @@ public class EhDB {
IOUtils.closeQuietly(os);
}
// Delete failed file
- file.delete();
return false;
} finally {
context.deleteDatabase(ehExportName);
@@ -680,8 +680,23 @@ public class EhDB {
* @param file The db file
* @return error string, null for no error
*/
- public static synchronized String importDB(Context context, File file) {
+ public static synchronized String importDB(Context context, Uri uri) {
try {
+ InputStream inputStream = context.getContentResolver().openInputStream(uri);
+ File file = File.createTempFile("importDatabase", "");
+ FileOutputStream outputStream = new FileOutputStream(file);
+ byte[] buff = new byte[1024];
+ int read;
+ if (inputStream != null) {
+ while ((read = inputStream.read(buff, 0, buff.length)) > 0) {
+ outputStream.write(buff, 0, read);
+ }
+ } else {
+ return context.getString(R.string.cant_read_the_file);
+ }
+ inputStream.close();
+ outputStream.close();
+
SQLiteDatabase db = SQLiteDatabase.openDatabase(
file.getPath(), null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
int newVersion = DaoMaster.SCHEMA_VERSION;
diff --git a/app/src/main/java/com/hippo/ehviewer/preference/ExportDataPreference.java b/app/src/main/java/com/hippo/ehviewer/preference/ExportDataPreference.java
deleted file mode 100644
index 940e3a6c9..000000000
--- a/app/src/main/java/com/hippo/ehviewer/preference/ExportDataPreference.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2019 Hippo Seven
- *
- * 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.hippo.ehviewer.preference;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-
-import com.hippo.ehviewer.AppConfig;
-import com.hippo.ehviewer.EhDB;
-import com.hippo.ehviewer.GetText;
-import com.hippo.ehviewer.R;
-import com.hippo.util.ReadableTime;
-
-import java.io.File;
-
-public class ExportDataPreference extends TaskPreference {
-
- public ExportDataPreference(Context context) {
- super(context);
- }
-
- public ExportDataPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public ExportDataPreference(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @NonNull
- @Override
- protected Task onCreateTask() {
- return new ExportDataTask(getContext());
- }
-
- private static class ExportDataTask extends Task {
-
- public ExportDataTask(@NonNull Context context) {
- super(context);
- }
-
- @Override
- protected Object doInBackground(Void... voids) {
- File dir = AppConfig.getExternalDataDir();
- if (dir != null) {
- File file = new File(dir, ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".db");
- if (EhDB.exportDB(getApplication(), file)) {
- return file;
- }
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(Object o) {
- Toast.makeText(getApplication(),
- (o instanceof File)
- ? GetText.getString(R.string.settings_advanced_export_data_to, ((File) o).getPath())
- : GetText.getString(R.string.settings_advanced_export_data_failed),
- Toast.LENGTH_SHORT).show();
- super.onPostExecute(o);
- }
- }
-}
diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java
index 6f17c538b..db99a76a8 100644
--- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java
+++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java
@@ -330,7 +330,6 @@ public final class MainActivity extends StageActivity
}
if (savedInstanceState == null) {
- onInit();
CommonOperations.checkUpdate(this, false);
checkDownloadLocation();
if (Settings.getCellularNetworkWarning()) {
@@ -362,12 +361,6 @@ public final class MainActivity extends StageActivity
}
}
- private void onInit() {
- // Check permission
- PermissionRequester.request(this, Manifest.permission.WRITE_EXTERNAL_STORAGE,
- getString(R.string.write_rationale), PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
- }
-
private void onRestore(Bundle savedInstanceState) {
mNavCheckedItem = savedInstanceState.getInt(KEY_NAV_CHECKED_ITEM);
}
diff --git a/app/src/main/java/com/hippo/ehviewer/ui/SettingsActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/SettingsActivity.java
index 010b4b320..9b7fce500 100644
--- a/app/src/main/java/com/hippo/ehviewer/ui/SettingsActivity.java
+++ b/app/src/main/java/com/hippo/ehviewer/ui/SettingsActivity.java
@@ -38,15 +38,6 @@ public final class SettingsActivity extends EhActivity {
private static final int REQUEST_CODE_FRAGMENT = 0;
- private static final String[] ENTRY_FRAGMENTS = {
- EhFragment.class.getName(),
- ReadFragment.class.getName(),
- DownloadFragment.class.getName(),
- AdvancedFragment.class.getName(),
- AboutFragment.class.getName(),
- PrivacyFragment.class.getName(),
- };
-
@Override
protected int getThemeResId(int theme) {
return R.style.AppTheme_Settings;
diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AdvancedFragment.java b/app/src/main/java/com/hippo/ehviewer/ui/fragment/AdvancedFragment.java
index 71bc2c2fd..a91fcc418 100644
--- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AdvancedFragment.java
+++ b/app/src/main/java/com/hippo/ehviewer/ui/fragment/AdvancedFragment.java
@@ -18,18 +18,23 @@ package com.hippo.ehviewer.ui.fragment;
import android.app.Activity;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Looper;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.hippo.ehviewer.AppConfig;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.EhDB;
+import com.hippo.ehviewer.GetText;
import com.hippo.ehviewer.R;
import com.hippo.util.LogCat;
import com.hippo.util.ReadableTime;
@@ -41,10 +46,15 @@ import java.util.Arrays;
public class AdvancedFragment extends PreferenceFragmentCompat
implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
+ private static final int REQUEST_CODE_EXPORT = 1;
+ private static final int REQUEST_CODE_IMPORT = 2;
+ private static final int REQUEST_DUMP_LOGCAT = 3;
+
private static final String KEY_DUMP_LOGCAT = "dump_logcat";
private static final String KEY_CLEAR_MEMORY_CACHE = "clear_memory_cache";
private static final String KEY_APP_LANGUAGE = "app_language";
private static final String KEY_IMPORT_DATA = "import_data";
+ private static final String KEY_EXPORT_DATA = "export_data";
private static void importData(final Context context) {
final File dir = AppConfig.getExternalDataDir();
@@ -60,11 +70,11 @@ public class AdvancedFragment extends PreferenceFragmentCompat
Arrays.sort(files);
new MaterialAlertDialogBuilder(context).setItems(files, (dialog, which) -> {
File file = new File(dir, files[which]);
- String error = EhDB.importDB(context, file);
- if (null == error) {
- error = context.getString(R.string.settings_advanced_import_data_successfully);
- }
- Toast.makeText(context, error, Toast.LENGTH_SHORT).show();
+ //String error = EhDB.importDB(context, file);
+ //if (null == error) {
+ // error = context.getString(R.string.settings_advanced_import_data_successfully);
+ //}
+ //Toast.makeText(context, error, Toast.LENGTH_SHORT).show();
}).show();
}
@@ -76,10 +86,12 @@ public class AdvancedFragment extends PreferenceFragmentCompat
Preference clearMemoryCache = findPreference(KEY_CLEAR_MEMORY_CACHE);
Preference appLanguage = findPreference(KEY_APP_LANGUAGE);
Preference importData = findPreference(KEY_IMPORT_DATA);
+ Preference exportData = findPreference(KEY_EXPORT_DATA);
dumpLogcat.setOnPreferenceClickListener(this);
clearMemoryCache.setOnPreferenceClickListener(this);
importData.setOnPreferenceClickListener(this);
+ exportData.setOnPreferenceClickListener(this);
appLanguage.setOnPreferenceChangeListener(this);
}
@@ -93,31 +105,108 @@ public class AdvancedFragment extends PreferenceFragmentCompat
public boolean onPreferenceClick(Preference preference) {
String key = preference.getKey();
if (KEY_DUMP_LOGCAT.equals(key)) {
- boolean ok;
- File file = null;
- File dir = AppConfig.getExternalLogcatDir();
- if (dir != null) {
- file = new File(dir, "logcat-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt");
- ok = LogCat.save(file);
- } else {
- ok = false;
- }
- Resources resources = getResources();
- Toast.makeText(getActivity(),
- ok ? resources.getString(R.string.settings_advanced_dump_logcat_to, file.getPath()) :
- resources.getString(R.string.settings_advanced_dump_logcat_failed), Toast.LENGTH_SHORT).show();
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("text/plain");
+ intent.putExtra(Intent.EXTRA_TITLE, "logcat-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt");
+ startActivityForResult(intent, REQUEST_DUMP_LOGCAT);
return true;
} else if (KEY_CLEAR_MEMORY_CACHE.equals(key)) {
((EhApplication) getActivity().getApplication()).clearMemoryCache();
Runtime.getRuntime().gc();
} else if (KEY_IMPORT_DATA.equals(key)) {
- importData(getActivity());
- getActivity().setResult(Activity.RESULT_OK);
+ Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("application/x-sqlite3");
+ startActivityForResult(intent, REQUEST_CODE_IMPORT);
+ return true;
+ } else if (KEY_EXPORT_DATA.equals(key)) {
+ Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.setType("application/x-sqlite3");
+ intent.putExtra(Intent.EXTRA_TITLE, ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".db");
+ startActivityForResult(intent, REQUEST_CODE_EXPORT);
return true;
}
return false;
}
+ @Override
+ protected void onActivityResult(PreferenceGroup group, int requestCode, int resultCode, Intent data) {
+ if (resultCode != Activity.RESULT_OK) {
+ return;
+ }
+ if (requestCode == REQUEST_CODE_EXPORT) {
+ if (data != null) {
+ Uri uri = data.getData();
+ if (uri != null) {
+ try {
+ AlertDialog alertDialog = new MaterialAlertDialogBuilder(requireActivity())
+ .setCancelable(false)
+ .setView(R.layout.preference_dialog_task)
+ .show();
+ new Thread(() -> {
+ boolean success = EhDB.exportDB(requireActivity(), uri);
+ requireActivity().runOnUiThread(() -> {
+ if (alertDialog.isShowing()) {
+ alertDialog.dismiss();
+ }
+ Toast.makeText(requireContext(),
+ (success)
+ ? GetText.getString(R.string.settings_advanced_export_data_to, uri.toString())
+ : GetText.getString(R.string.settings_advanced_export_data_failed),
+ Toast.LENGTH_SHORT).show();
+ });
+ }).start();
+ } catch (Exception e) {
+ GetText.getString(R.string.settings_advanced_export_data_failed);
+ }
+ }
+ }
+ } else if (requestCode == REQUEST_CODE_IMPORT) {
+ if (data != null) {
+ Uri uri = data.getData();
+ if (uri != null) {
+ try {
+ AlertDialog alertDialog = new MaterialAlertDialogBuilder(requireActivity())
+ .setCancelable(false)
+ .setView(R.layout.preference_dialog_task)
+ .show();
+ new Thread(() -> {
+ final String error = EhDB.importDB(requireActivity(), uri);
+ requireActivity().runOnUiThread(() -> {
+ if (alertDialog.isShowing()) {
+ alertDialog.dismiss();
+ }
+ if (null == error) {
+ Toast.makeText(requireContext(), getString(R.string.settings_advanced_import_data_successfully), Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(requireContext(), error, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }).start();
+ } catch (Exception e) {
+ Toast.makeText(requireContext(), e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+ } else if (requestCode == REQUEST_DUMP_LOGCAT) {
+ if (data != null) {
+ Uri uri = data.getData();
+ if (uri != null) {
+ try {
+ boolean ok = LogCat.save(requireActivity().getContentResolver().openOutputStream(uri));
+ Toast.makeText(getActivity(),
+ ok ? getString(R.string.settings_advanced_dump_logcat_to, uri.toString()) :
+ getString(R.string.settings_advanced_dump_logcat_failed), Toast.LENGTH_SHORT).show();
+ }catch (Exception e){
+ Toast.makeText(getActivity(), getString(R.string.settings_advanced_dump_logcat_failed), Toast.LENGTH_SHORT).show();}
+ }
+ }
+ }
+ super.onActivityResult(group, requestCode, resultCode, data);
+ }
+
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String key = preference.getKey();
diff --git a/app/src/main/java/com/hippo/util/LogCat.java b/app/src/main/java/com/hippo/util/LogCat.java
index b49f421a9..07020081d 100644
--- a/app/src/main/java/com/hippo/util/LogCat.java
+++ b/app/src/main/java/com/hippo/util/LogCat.java
@@ -16,26 +16,20 @@
package com.hippo.util;
-import com.hippo.yorozuya.FileUtils;
import com.hippo.yorozuya.IOUtils;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
public final class LogCat {
private LogCat() {
}
- public static boolean save(File file) {
- if (!FileUtils.ensureFile(file)) {
- return false;
- }
-
+ public static boolean save(OutputStream outputStream) {
try {
Process p = Runtime.getRuntime().exec("logcat -d");
- IOUtils.copy(p.getInputStream(), new FileOutputStream(file));
+ IOUtils.copy(p.getInputStream(), outputStream);
return true;
} catch (IOException e) {
e.printStackTrace();
diff --git a/app/src/main/res/xml/advanced_settings.xml b/app/src/main/res/xml/advanced_settings.xml
index 2cdff6065..cd5af2a4c 100644
--- a/app/src/main/res/xml/advanced_settings.xml
+++ b/app/src/main/res/xml/advanced_settings.xml
@@ -89,7 +89,7 @@
app:activity="com.hippo.ehviewer.ui.HostsActivity"
app:iconSpaceReserved="false" />
-