Merge pull request #10731 from osmandapp/DataStorageRefactoring
Data storage refactoring
This commit is contained in:
commit
dedea0c45e
17 changed files with 905 additions and 784 deletions
|
@ -9,7 +9,8 @@
|
|||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/card_row_min_height">
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/card_row_min_height">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@android:id/icon"
|
||||
|
@ -31,11 +32,15 @@
|
|||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:paddingLeft="@dimen/content_padding"
|
||||
android:paddingStart="@dimen/content_padding"
|
||||
android:paddingRight="0dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingTop="@dimen/content_padding_half"
|
||||
android:paddingBottom="@dimen/content_padding_half"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:typeface="@string/font_roboto_regular"
|
||||
tools:text="Internal application memory"
|
||||
android:paddingStart="@dimen/content_padding" />
|
||||
tools:text="Internal application memory" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/memory"
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
-->
|
||||
|
||||
<string name="hillshade_slope_contour_lines">Hillshade / Slope / Contour lines</string>
|
||||
<string name="toast_select_edits_for_upload">Select edits for upload</string>
|
||||
<string name="uploaded_count">Uploaded %1$d of %2$d</string>
|
||||
<string name="uploading_count">Uploading %1$d of %2$d</string>
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
android:title="@string/shared_string_maps"/>
|
||||
|
||||
<Preference
|
||||
android:key="contour_lines_and_hillshade_memory"
|
||||
android:key="terrain_memory_used"
|
||||
android:layout="@layout/data_storage_memory_used_item"
|
||||
android:icon="@drawable/ic_map"
|
||||
android:title="@string/contour_lines_and_hillshade"/>
|
||||
android:title="@string/hillshade_slope_contour_lines"/>
|
||||
|
||||
<Preference
|
||||
android:key="tracks_memory_used"
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
android:layout="@layout/preference_with_descr"
|
||||
android:persistent="false"
|
||||
android:title="@string/application_dir"
|
||||
app:fragment="net.osmand.plus.settings.fragments.DataStorageFragment"
|
||||
app:fragment="net.osmand.plus.settings.datastorage.DataStorageFragment"
|
||||
tools:icon="@drawable/ic_action_folder" />
|
||||
|
||||
<Preference
|
||||
|
|
|
@ -139,7 +139,7 @@ import net.osmand.plus.settings.backend.OsmandSettings;
|
|||
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
|
||||
import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType;
|
||||
import net.osmand.plus.settings.fragments.ConfigureProfileFragment;
|
||||
import net.osmand.plus.settings.fragments.DataStorageFragment;
|
||||
import net.osmand.plus.settings.datastorage.DataStorageFragment;
|
||||
import net.osmand.plus.track.TrackAppearanceFragment;
|
||||
import net.osmand.plus.track.TrackMenuFragment;
|
||||
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
|
||||
|
|
|
@ -19,13 +19,13 @@ import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
|
|||
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
|
||||
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
|
||||
import net.osmand.plus.settings.fragments.DataStorageMenuItem;
|
||||
import net.osmand.plus.settings.datastorage.item.StorageItem;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static net.osmand.plus.settings.fragments.DataStorageHelper.MANUALLY_SPECIFIED;
|
||||
import static net.osmand.plus.settings.datastorage.DataStorageHelper.MANUALLY_SPECIFIED;
|
||||
|
||||
public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
|
||||
|
||||
|
@ -39,8 +39,8 @@ public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
|
|||
public final static String MOVE_DATA = "move_data";
|
||||
public final static String CHOSEN_DIRECTORY = "chosen_storage";
|
||||
|
||||
private DataStorageMenuItem currentDirectory;
|
||||
private DataStorageMenuItem newDirectory;
|
||||
private StorageItem currentDirectory;
|
||||
private StorageItem newDirectory;
|
||||
|
||||
@Override
|
||||
public void createMenuItems(Bundle savedInstanceState) {
|
||||
|
@ -126,11 +126,11 @@ public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
|
|||
items.add(baseItem);
|
||||
}
|
||||
|
||||
public void setCurrentDirectory(DataStorageMenuItem currentDirectory) {
|
||||
public void setCurrentDirectory(StorageItem currentDirectory) {
|
||||
this.currentDirectory = currentDirectory;
|
||||
}
|
||||
|
||||
public void setNewDirectory(DataStorageMenuItem newDirectory) {
|
||||
public void setNewDirectory(StorageItem newDirectory) {
|
||||
this.newDirectory = newDirectory;
|
||||
}
|
||||
|
||||
|
@ -158,8 +158,8 @@ public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static boolean showInstance(FragmentManager fm, String prefId, DataStorageMenuItem currentDirectory,
|
||||
DataStorageMenuItem newDirectory, Fragment target, boolean usedOnMap) {
|
||||
public static boolean showInstance(FragmentManager fm, String prefId, StorageItem currentDirectory,
|
||||
StorageItem newDirectory, Fragment target, boolean usedOnMap) {
|
||||
try {
|
||||
if (fm.findFragmentByTag(TAG) == null) {
|
||||
Bundle args = new Bundle();
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package net.osmand.plus.settings.fragments;
|
||||
package net.osmand.plus.settings.datastorage;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
@ -26,7 +25,6 @@ import net.osmand.AndroidUtils;
|
|||
import net.osmand.FileUtils;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
|
@ -34,20 +32,21 @@ import net.osmand.plus.activities.OsmandActionBarActivity;
|
|||
import net.osmand.plus.download.DownloadActivity;
|
||||
import net.osmand.plus.settings.bottomsheets.ChangeDataStorageBottomSheet;
|
||||
import net.osmand.plus.settings.bottomsheets.SelectFolderBottomSheet;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.plus.settings.datastorage.item.MemoryItem;
|
||||
import net.osmand.plus.settings.datastorage.item.StorageItem;
|
||||
import net.osmand.plus.settings.datastorage.task.MoveFilesTask;
|
||||
import net.osmand.plus.settings.datastorage.task.RefreshUsedMemoryTask;
|
||||
import net.osmand.plus.settings.datastorage.task.ReloadDataTask;
|
||||
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static net.osmand.plus.settings.fragments.DataStorageHelper.INTERNAL_STORAGE;
|
||||
import static net.osmand.plus.settings.fragments.DataStorageHelper.MANUALLY_SPECIFIED;
|
||||
import static net.osmand.plus.settings.fragments.DataStorageHelper.OTHER_MEMORY;
|
||||
import static net.osmand.plus.settings.fragments.DataStorageHelper.TILES_MEMORY;
|
||||
import static net.osmand.plus.settings.datastorage.DataStorageHelper.INTERNAL_STORAGE;
|
||||
import static net.osmand.plus.settings.datastorage.DataStorageHelper.MANUALLY_SPECIFIED;
|
||||
import static net.osmand.plus.settings.datastorage.DataStorageHelper.OTHER_MEMORY;
|
||||
import static net.osmand.plus.settings.datastorage.DataStorageHelper.TILES_MEMORY;
|
||||
import static net.osmand.plus.settings.bottomsheets.ChangeDataStorageBottomSheet.CHOSEN_DIRECTORY;
|
||||
import static net.osmand.plus.settings.bottomsheets.ChangeDataStorageBottomSheet.MOVE_DATA;
|
||||
import static net.osmand.plus.settings.bottomsheets.SelectFolderBottomSheet.NEW_PATH;
|
||||
|
@ -60,17 +59,17 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
private final static String CHANGE_DIRECTORY_BUTTON = "change_directory";
|
||||
private final static String OSMAND_USAGE = "osmand_usage";
|
||||
|
||||
private ArrayList<DataStorageMenuItem> menuItems;
|
||||
private ArrayList<DataStorageMemoryItem> memoryItems;
|
||||
private ArrayList<StorageItem> storageItems;
|
||||
private ArrayList<MemoryItem> memoryItems;
|
||||
private ArrayList<CheckBoxPreference> dataStorageRadioButtonsGroup;
|
||||
private Preference changeButton;
|
||||
private DataStorageMenuItem currentDataStorage;
|
||||
private StorageItem currentDataStorage;
|
||||
private String tmpManuallySpecifiedPath;
|
||||
private DataStorageHelper dataStorageHelper;
|
||||
private boolean calculateTilesBtnPressed;
|
||||
|
||||
private DataStorageHelper.RefreshMemoryUsedInfo calculateMemoryTask;
|
||||
private DataStorageHelper.RefreshMemoryUsedInfo calculateTilesMemoryTask;
|
||||
private RefreshUsedMemoryTask calculateMemoryTask;
|
||||
private RefreshUsedMemoryTask calculateTilesMemoryTask;
|
||||
|
||||
private OsmandApplication app;
|
||||
private OsmandActionBarActivity activity;
|
||||
|
@ -95,11 +94,11 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
return;
|
||||
}
|
||||
|
||||
menuItems = dataStorageHelper.getStorageItems();
|
||||
storageItems = dataStorageHelper.getStorageItems();
|
||||
memoryItems = dataStorageHelper.getMemoryInfoItems();
|
||||
dataStorageRadioButtonsGroup = new ArrayList<>();
|
||||
|
||||
for (DataStorageMenuItem item : menuItems) {
|
||||
for (StorageItem item : storageItems) {
|
||||
CheckBoxPreference preference = new CheckBoxPreference(activity);
|
||||
preference.setKey(item.getKey());
|
||||
preference.setTitle(item.getTitle());
|
||||
|
@ -136,7 +135,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
Bundle resultData = (Bundle) newValue;
|
||||
if (resultData.containsKey(ChangeDataStorageBottomSheet.TAG)) {
|
||||
boolean moveMaps = resultData.getBoolean(MOVE_DATA);
|
||||
DataStorageMenuItem newDataStorage = resultData.getParcelable(CHOSEN_DIRECTORY);
|
||||
StorageItem newDataStorage = resultData.getParcelable(CHOSEN_DIRECTORY);
|
||||
if (newDataStorage != null) {
|
||||
if (tmpManuallySpecifiedPath != null) {
|
||||
String directory = tmpManuallySpecifiedPath;
|
||||
|
@ -154,9 +153,9 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
if (pathChanged) {
|
||||
tmpManuallySpecifiedPath = resultData.getString(NEW_PATH);
|
||||
if (tmpManuallySpecifiedPath != null) {
|
||||
DataStorageMenuItem manuallySpecified = null;
|
||||
StorageItem manuallySpecified = null;
|
||||
try {
|
||||
manuallySpecified = (DataStorageMenuItem) dataStorageHelper.getManuallySpecified().clone();
|
||||
manuallySpecified = (StorageItem) dataStorageHelper.getManuallySpecified().clone();
|
||||
manuallySpecified.setDirectory(tmpManuallySpecifiedPath);
|
||||
} catch (CloneNotSupportedException e) {
|
||||
return false;
|
||||
|
@ -170,7 +169,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
//show necessary dialog
|
||||
String key = preference.getKey();
|
||||
if (key != null) {
|
||||
DataStorageMenuItem newDataStorage = dataStorageHelper.getStorage(key);
|
||||
StorageItem newDataStorage = dataStorageHelper.getStorage(key);
|
||||
if (newDataStorage != null) {
|
||||
if (!currentDataStorage.getKey().equals(newDataStorage.getKey())) {
|
||||
if (newDataStorage.getType() == OsmandSettings.EXTERNAL_STORAGE_TYPE_DEFAULT
|
||||
|
@ -212,7 +211,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
|
||||
final View itemView = holder.itemView;
|
||||
if (preference instanceof CheckBoxPreference) {
|
||||
DataStorageMenuItem item = dataStorageHelper.getStorage(key);
|
||||
StorageItem item = dataStorageHelper.getStorage(key);
|
||||
if (item != null) {
|
||||
TextView tvTitle = itemView.findViewById(android.R.id.title);
|
||||
TextView tvSummary = itemView.findViewById(R.id.summary);
|
||||
|
@ -267,7 +266,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
TextView tvSummary = itemView.findViewById(R.id.summary);
|
||||
tvSummary.setText(DataStorageHelper.getFormattedMemoryInfo(totalUsageBytes, memoryUnitsFormats));
|
||||
} else {
|
||||
for (DataStorageMemoryItem mi : memoryItems) {
|
||||
for (MemoryItem mi : memoryItems) {
|
||||
if (key.equals(mi.getKey())) {
|
||||
TextView tvMemory = itemView.findViewById(R.id.memory);
|
||||
String summary = "";
|
||||
|
@ -326,7 +325,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
}
|
||||
|
||||
private void showFolderSelectionDialog() {
|
||||
DataStorageMenuItem manuallySpecified = dataStorageHelper.getManuallySpecified();
|
||||
StorageItem manuallySpecified = dataStorageHelper.getManuallySpecified();
|
||||
if (manuallySpecified != null) {
|
||||
SelectFolderBottomSheet.showInstance(getFragmentManager(), manuallySpecified.getKey(),
|
||||
manuallySpecified.getDirectory(), DataStorageFragment.this,
|
||||
|
@ -335,11 +334,11 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
}
|
||||
}
|
||||
|
||||
private void moveData(final DataStorageMenuItem currentStorage, final DataStorageMenuItem newStorage) {
|
||||
private void moveData(final StorageItem currentStorage, final StorageItem newStorage) {
|
||||
File fromDirectory = new File(currentStorage.getDirectory());
|
||||
File toDirectory = new File(newStorage.getDirectory());
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
MoveFilesToDifferentDirectory task = new MoveFilesToDifferentDirectory(activity, fromDirectory, toDirectory) {
|
||||
MoveFilesTask task = new MoveFilesTask(activity, fromDirectory, toDirectory) {
|
||||
|
||||
|
||||
@NonNull
|
||||
|
@ -405,7 +404,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void confirm(OsmandApplication app, OsmandActionBarActivity activity, DataStorageMenuItem newStorageDirectory, boolean silentRestart) {
|
||||
private void confirm(OsmandApplication app, OsmandActionBarActivity activity, StorageItem newStorageDirectory, boolean silentRestart) {
|
||||
String newDirectory = newStorageDirectory.getDirectory();
|
||||
int type = newStorageDirectory.getType();
|
||||
File newDirectoryFile = new File(newDirectory);
|
||||
|
@ -454,7 +453,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
}
|
||||
|
||||
protected void reloadData() {
|
||||
new ReloadData(activity, app).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
new ReloadDataTask(activity, app).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -463,204 +462,10 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onFinishUpdating(String taskKey) {
|
||||
public void onFinishUpdating(String tag) {
|
||||
updateAllSettings();
|
||||
if (taskKey != null && taskKey.equals(TILES_MEMORY)) {
|
||||
if (tag != null && tag.equals(TILES_MEMORY)) {
|
||||
app.getSettings().OSMAND_USAGE_SPACE.set(dataStorageHelper.getTotalUsedBytes());
|
||||
}
|
||||
}
|
||||
|
||||
public static class MoveFilesToDifferentDirectory extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
protected WeakReference<OsmandActionBarActivity> activity;
|
||||
private WeakReference<Context> context;
|
||||
private File from;
|
||||
private File to;
|
||||
protected ProgressImplementation progress;
|
||||
private Runnable runOnSuccess;
|
||||
private int movedCount;
|
||||
private long movedSize;
|
||||
private int copiedCount;
|
||||
private long copiedSize;
|
||||
private int failedCount;
|
||||
private long failedSize;
|
||||
private String exceptionMessage;
|
||||
|
||||
public MoveFilesToDifferentDirectory(OsmandActionBarActivity activity, File from, File to) {
|
||||
this.activity = new WeakReference<>(activity);
|
||||
this.context = new WeakReference<>((Context) activity);
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public void setRunOnSuccess(Runnable runOnSuccess) {
|
||||
this.runOnSuccess = runOnSuccess;
|
||||
}
|
||||
|
||||
public int getMovedCount() {
|
||||
return movedCount;
|
||||
}
|
||||
|
||||
public int getCopiedCount() {
|
||||
return copiedCount;
|
||||
}
|
||||
|
||||
public int getFailedCount() {
|
||||
return failedCount;
|
||||
}
|
||||
|
||||
public long getMovedSize() {
|
||||
return movedSize;
|
||||
}
|
||||
|
||||
public long getCopiedSize() {
|
||||
return copiedSize;
|
||||
}
|
||||
|
||||
public long getFailedSize() {
|
||||
return failedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Context ctx = context.get();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
movedCount = 0;
|
||||
copiedCount = 0;
|
||||
failedCount = 0;
|
||||
progress = ProgressImplementation.createProgressDialog(
|
||||
ctx, ctx.getString(R.string.copying_osmand_files),
|
||||
ctx.getString(R.string.copying_osmand_files_descr, to.getPath()),
|
||||
ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
Context ctx = context.get();
|
||||
if (ctx == null) {
|
||||
return;
|
||||
}
|
||||
if (result != null) {
|
||||
if (result.booleanValue() && runOnSuccess != null) {
|
||||
runOnSuccess.run();
|
||||
} else if (!result.booleanValue()) {
|
||||
Toast.makeText(ctx, ctx.getString(R.string.shared_string_io_error) + ": " + exceptionMessage, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void movingFiles(File f, File t, int depth) throws IOException {
|
||||
Context ctx = context.get();
|
||||
if (ctx == null) {
|
||||
return;
|
||||
}
|
||||
if (depth <= 2) {
|
||||
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), -1);
|
||||
}
|
||||
if (f.isDirectory()) {
|
||||
t.mkdirs();
|
||||
File[] lf = f.listFiles();
|
||||
if (lf != null) {
|
||||
for (int i = 0; i < lf.length; i++) {
|
||||
if (lf[i] != null) {
|
||||
movingFiles(lf[i], new File(t, lf[i].getName()), depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
f.delete();
|
||||
} else if (f.isFile()) {
|
||||
if (t.exists()) {
|
||||
Algorithms.removeAllFiles(t);
|
||||
}
|
||||
boolean rnm = false;
|
||||
long fileSize = f.length();
|
||||
try {
|
||||
rnm = f.renameTo(t);
|
||||
movedCount++;
|
||||
movedSize += fileSize;
|
||||
} catch (RuntimeException e) {
|
||||
}
|
||||
if (!rnm) {
|
||||
FileInputStream fin = new FileInputStream(f);
|
||||
FileOutputStream fout = new FileOutputStream(t);
|
||||
try {
|
||||
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), (int) (f.length() / 1024));
|
||||
Algorithms.streamCopy(fin, fout, progress, 1024);
|
||||
copiedCount++;
|
||||
copiedSize += fileSize;
|
||||
} catch (IOException e) {
|
||||
failedCount++;
|
||||
failedSize += fileSize;
|
||||
} finally {
|
||||
fin.close();
|
||||
fout.close();
|
||||
}
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
if (depth <= 2) {
|
||||
progress.finishTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
to.mkdirs();
|
||||
try {
|
||||
movingFiles(from, to, 0);
|
||||
} catch (IOException e) {
|
||||
exceptionMessage = e.getMessage();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ReloadData extends AsyncTask<Void, Void, Boolean> {
|
||||
private WeakReference<Context> ctx;
|
||||
protected ProgressImplementation progress;
|
||||
private OsmandApplication app;
|
||||
|
||||
public ReloadData(Context ctx, OsmandApplication app) {
|
||||
this.ctx = new WeakReference<>(ctx);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Context c = ctx.get();
|
||||
if (c == null) {
|
||||
return;
|
||||
}
|
||||
progress = ProgressImplementation.createProgressDialog(c, c.getString(R.string.loading_data),
|
||||
c.getString(R.string.loading_data), ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
app.getResourceManager().reloadIndexes(progress, new ArrayList<String>());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
package net.osmand.plus.settings.datastorage;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.ValueHolder;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.settings.datastorage.item.DirectoryItem;
|
||||
import net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType;
|
||||
import net.osmand.plus.settings.datastorage.item.MemoryItem;
|
||||
import net.osmand.plus.settings.datastorage.item.StorageItem;
|
||||
import net.osmand.plus.settings.datastorage.task.RefreshUsedMemoryTask;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static net.osmand.IndexConstants.AV_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.BACKUP_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.GPX_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.MAPS_PATH;
|
||||
import static net.osmand.IndexConstants.ROADS_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.SRTM_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.TILES_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.WIKIVOYAGE_INDEX_DIR;
|
||||
import static net.osmand.IndexConstants.WIKI_INDEX_DIR;
|
||||
import static net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType.EXTENSIONS;
|
||||
import static net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType.PREFIX;
|
||||
|
||||
public class DataStorageHelper {
|
||||
public final static String INTERNAL_STORAGE = "internal_storage";
|
||||
public final static String EXTERNAL_STORAGE = "external_storage";
|
||||
public final static String SHARED_STORAGE = "shared_storage";
|
||||
public final static String MULTIUSER_STORAGE = "multiuser_storage";
|
||||
public final static String MANUALLY_SPECIFIED = "manually_specified";
|
||||
|
||||
public final static String MAPS_MEMORY = "maps_memory_used";
|
||||
public final static String TERRAIN_MEMORY = "terrain_memory_used";
|
||||
public final static String TRACKS_MEMORY = "tracks_memory_used";
|
||||
public final static String NOTES_MEMORY = "notes_memory_used";
|
||||
public final static String TILES_MEMORY = "tiles_memory_used";
|
||||
public final static String OTHER_MEMORY = "other_memory_used";
|
||||
|
||||
private OsmandApplication app;
|
||||
private ArrayList<StorageItem> storageItems = new ArrayList<>();
|
||||
private StorageItem currentDataStorage;
|
||||
private StorageItem manuallySpecified;
|
||||
|
||||
private ArrayList<MemoryItem> memoryItems = new ArrayList<>();
|
||||
private MemoryItem mapsMemory;
|
||||
private MemoryItem terrainMemory;
|
||||
private MemoryItem tracksMemory;
|
||||
private MemoryItem notesMemory;
|
||||
private MemoryItem tilesMemory;
|
||||
private MemoryItem otherMemory;
|
||||
|
||||
private int currentStorageType;
|
||||
private String currentStoragePath;
|
||||
|
||||
public DataStorageHelper(@NonNull OsmandApplication app) {
|
||||
this.app = app;
|
||||
prepareData();
|
||||
}
|
||||
|
||||
private void prepareData() {
|
||||
initStorageItems();
|
||||
initUsedMemoryItems();
|
||||
}
|
||||
|
||||
private void initStorageItems() {
|
||||
OsmandSettings settings = app.getSettings();
|
||||
if (settings.getExternalStorageDirectoryTypeV19() >= 0) {
|
||||
currentStorageType = settings.getExternalStorageDirectoryTypeV19();
|
||||
} else {
|
||||
ValueHolder<Integer> vh = new ValueHolder<Integer>();
|
||||
if (vh.value != null && vh.value >= 0) {
|
||||
currentStorageType = vh.value;
|
||||
} else {
|
||||
currentStorageType = 0;
|
||||
}
|
||||
}
|
||||
currentStoragePath = settings.getExternalStorageDirectory().getAbsolutePath();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
|
||||
//internal storage
|
||||
String path = settings.getInternalAppPath().getAbsolutePath();
|
||||
File dir = new File(path);
|
||||
int iconId = R.drawable.ic_action_phone;
|
||||
|
||||
StorageItem internalStorageItem = StorageItem.builder()
|
||||
.setKey(INTERNAL_STORAGE)
|
||||
.setTitle(app.getString(R.string.storage_directory_internal_app))
|
||||
.setDirectory(path)
|
||||
.setDescription(app.getString(R.string.internal_app_storage_description))
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_INTERNAL_FILE)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(internalStorageItem);
|
||||
|
||||
//shared storage
|
||||
dir = settings.getDefaultInternalStorage();
|
||||
path = dir.getAbsolutePath();
|
||||
iconId = R.drawable.ic_action_phone;
|
||||
|
||||
StorageItem sharedStorageItem = StorageItem.builder()
|
||||
.setKey(SHARED_STORAGE)
|
||||
.setTitle(app.getString(R.string.storage_directory_shared))
|
||||
.setDirectory(path)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_DEFAULT)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(sharedStorageItem);
|
||||
|
||||
//external storage
|
||||
File[] externals = app.getExternalFilesDirs(null);
|
||||
if (externals != null) {
|
||||
int i = 0;
|
||||
for (File external : externals) {
|
||||
if (external != null) {
|
||||
++i;
|
||||
dir = external;
|
||||
path = dir.getAbsolutePath();
|
||||
iconId = getIconForStorageType(dir);
|
||||
StorageItem externalStorageItem = StorageItem.builder()
|
||||
.setKey(EXTERNAL_STORAGE + i)
|
||||
.setTitle(app.getString(R.string.storage_directory_external) + " " + i)
|
||||
.setDirectory(path)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_EXTERNAL_FILE)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(externalStorageItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//multi user storage
|
||||
File[] obbDirs = app.getObbDirs();
|
||||
if (obbDirs != null) {
|
||||
int i = 0;
|
||||
for (File obb : obbDirs) {
|
||||
if (obb != null) {
|
||||
++i;
|
||||
dir = obb;
|
||||
path = dir.getAbsolutePath();
|
||||
iconId = getIconForStorageType(dir);
|
||||
StorageItem multiuserStorageItem = StorageItem.builder()
|
||||
.setKey(MULTIUSER_STORAGE + i)
|
||||
.setTitle(app.getString(R.string.storage_directory_multiuser) + " " + i)
|
||||
.setDirectory(path)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_OBB)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(multiuserStorageItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//manually specified storage
|
||||
manuallySpecified = StorageItem.builder()
|
||||
.setKey(MANUALLY_SPECIFIED)
|
||||
.setTitle(app.getString(R.string.storage_directory_manual))
|
||||
.setDirectory(currentStoragePath)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_SPECIFIED)
|
||||
.setIconResId(R.drawable.ic_action_folder)
|
||||
.createItem();
|
||||
storageItems.add(manuallySpecified);
|
||||
|
||||
if (currentDataStorage == null) {
|
||||
currentDataStorage = manuallySpecified;
|
||||
}
|
||||
}
|
||||
|
||||
private void initUsedMemoryItems() {
|
||||
mapsMemory = MemoryItem.builder()
|
||||
.setKey(MAPS_MEMORY)
|
||||
.setExtensions(IndexConstants.BINARY_MAP_INDEX_EXT)
|
||||
.setDirectories(
|
||||
createDirectory(MAPS_PATH, false, EXTENSIONS, true),
|
||||
createDirectory(ROADS_INDEX_DIR, true, EXTENSIONS, true),
|
||||
createDirectory(WIKI_INDEX_DIR, true, EXTENSIONS, true),
|
||||
createDirectory(WIKIVOYAGE_INDEX_DIR, true, EXTENSIONS, true),
|
||||
createDirectory(BACKUP_INDEX_DIR, true, EXTENSIONS, true))
|
||||
.createItem();
|
||||
memoryItems.add(mapsMemory);
|
||||
|
||||
terrainMemory = MemoryItem.builder()
|
||||
.setKey(TERRAIN_MEMORY)
|
||||
.setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
|
||||
.setDirectories(
|
||||
createDirectory(SRTM_INDEX_DIR, true, EXTENSIONS, true),
|
||||
createDirectory(TILES_INDEX_DIR, false, PREFIX, false))
|
||||
.setPrefixes("Hillshade", "Slope")
|
||||
.createItem();
|
||||
memoryItems.add(terrainMemory);
|
||||
|
||||
tracksMemory = MemoryItem.builder()
|
||||
.setKey(TRACKS_MEMORY)
|
||||
// .setExtensions(IndexConstants.GPX_FILE_EXT, ".gpx.bz2")
|
||||
.setDirectories(
|
||||
createDirectory(GPX_INDEX_DIR, true, EXTENSIONS, true))
|
||||
.createItem();
|
||||
memoryItems.add(tracksMemory);
|
||||
|
||||
notesMemory = MemoryItem.builder()
|
||||
.setKey(NOTES_MEMORY)
|
||||
// .setExtensions("")
|
||||
.setDirectories(
|
||||
createDirectory(AV_INDEX_DIR, true, EXTENSIONS, true))
|
||||
.createItem();
|
||||
memoryItems.add(notesMemory);
|
||||
|
||||
tilesMemory = MemoryItem.builder()
|
||||
.setKey(TILES_MEMORY)
|
||||
// .setExtensions("")
|
||||
.setDirectories(
|
||||
createDirectory(TILES_INDEX_DIR, true, EXTENSIONS, true))
|
||||
.createItem();
|
||||
memoryItems.add(tilesMemory);
|
||||
|
||||
otherMemory = MemoryItem.builder()
|
||||
.setKey(OTHER_MEMORY)
|
||||
.createItem();
|
||||
memoryItems.add(otherMemory);
|
||||
}
|
||||
|
||||
public ArrayList<StorageItem> getStorageItems() {
|
||||
return storageItems;
|
||||
}
|
||||
|
||||
private int getIconForStorageType(File dir) {
|
||||
return R.drawable.ic_action_folder;
|
||||
}
|
||||
|
||||
public StorageItem getCurrentStorage() {
|
||||
return currentDataStorage;
|
||||
}
|
||||
|
||||
private void addItem(StorageItem item) {
|
||||
if (currentStorageType == item.getType() && currentStoragePath.equals(item.getDirectory())) {
|
||||
currentDataStorage = item;
|
||||
}
|
||||
storageItems.add(item);
|
||||
}
|
||||
|
||||
public StorageItem getManuallySpecified() {
|
||||
return manuallySpecified;
|
||||
}
|
||||
|
||||
public StorageItem getStorage(String key) {
|
||||
if (storageItems != null && key != null) {
|
||||
for (StorageItem storageItem : storageItems) {
|
||||
if (key.equals(storageItem.getKey())) {
|
||||
return storageItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayList<MemoryItem> getMemoryInfoItems() {
|
||||
return memoryItems;
|
||||
}
|
||||
|
||||
public RefreshUsedMemoryTask calculateMemoryUsedInfo(UpdateMemoryInfoUIAdapter uiAdapter) {
|
||||
File rootDir = new File(currentStoragePath);
|
||||
RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(uiAdapter, otherMemory, rootDir, null, null, OTHER_MEMORY);
|
||||
task.execute(mapsMemory, terrainMemory, tracksMemory, notesMemory);
|
||||
return task;
|
||||
}
|
||||
|
||||
public RefreshUsedMemoryTask calculateTilesMemoryUsed(UpdateMemoryInfoUIAdapter listener) {
|
||||
File rootDir = new File(tilesMemory.getDirectories()[0].getAbsolutePath());
|
||||
RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(listener, otherMemory, rootDir, null, terrainMemory.getPrefixes(), TILES_MEMORY);
|
||||
task.execute(tilesMemory);
|
||||
return task;
|
||||
}
|
||||
|
||||
public long getTotalUsedBytes() {
|
||||
long total = 0;
|
||||
if (memoryItems != null && memoryItems.size() > 0) {
|
||||
for (MemoryItem mi : memoryItems) {
|
||||
total += mi.getUsedMemoryBytes();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public DirectoryItem createDirectory(@NonNull String relativePath,
|
||||
boolean processInternalDirectories,
|
||||
CheckingType checkingType,
|
||||
boolean addUnmatchedToOtherMemory) {
|
||||
String path = app.getAppPath(relativePath).getAbsolutePath();
|
||||
return new DirectoryItem(path, processInternalDirectories, checkingType, addUnmatchedToOtherMemory);
|
||||
}
|
||||
|
||||
public static String getFormattedMemoryInfo(long bytes, String[] formatStrings) {
|
||||
int type = 0;
|
||||
double memory = (double) bytes / 1024;
|
||||
while (memory > 1024 && type < formatStrings.length) {
|
||||
++type;
|
||||
memory = memory / 1024;
|
||||
}
|
||||
String formattedUsed = new DecimalFormat("#.##").format(memory);
|
||||
return String.format(formatStrings[type], formattedUsed);
|
||||
}
|
||||
|
||||
public interface UpdateMemoryInfoUIAdapter {
|
||||
|
||||
void onMemoryInfoUpdate();
|
||||
|
||||
void onFinishUpdating(String tag);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package net.osmand.plus.settings.datastorage.item;
|
||||
|
||||
public class DirectoryItem {
|
||||
|
||||
private final String absolutePath;
|
||||
private final boolean processInternalDirectories;
|
||||
private final CheckingType checkingType;
|
||||
private final boolean addUnmatchedToOtherMemory;
|
||||
|
||||
public enum CheckingType {
|
||||
EXTENSIONS,
|
||||
PREFIX
|
||||
}
|
||||
|
||||
public DirectoryItem(String absolutePath,
|
||||
boolean processInternalDirectories,
|
||||
CheckingType checkingType,
|
||||
boolean addUnmatchedToOtherMemory) {
|
||||
this.absolutePath = absolutePath;
|
||||
this.processInternalDirectories = processInternalDirectories;
|
||||
this.checkingType = checkingType;
|
||||
this.addUnmatchedToOtherMemory = addUnmatchedToOtherMemory;
|
||||
}
|
||||
|
||||
public String getAbsolutePath() {
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
public boolean shouldProcessInternalDirectories() {
|
||||
return processInternalDirectories;
|
||||
}
|
||||
|
||||
public CheckingType getCheckingType() {
|
||||
return checkingType;
|
||||
}
|
||||
|
||||
public boolean shouldAddUnmatchedToOtherMemory() {
|
||||
return addUnmatchedToOtherMemory;
|
||||
}
|
||||
}
|
|
@ -1,16 +1,18 @@
|
|||
package net.osmand.plus.settings.fragments;
|
||||
package net.osmand.plus.settings.datastorage.item;
|
||||
|
||||
public class DataStorageMemoryItem {
|
||||
public final static int EXTENSIONS = 0;
|
||||
public final static int PREFIX = 1;
|
||||
public class MemoryItem {
|
||||
|
||||
private String key;
|
||||
private String[] extensions;
|
||||
private String[] prefixes;
|
||||
private Directory[] directories;
|
||||
private final String[] extensions;
|
||||
private final String[] prefixes;
|
||||
private final DirectoryItem[] directories;
|
||||
private long usedMemoryBytes;
|
||||
|
||||
private DataStorageMemoryItem(String key, String[] extensions, String[] prefixes, long usedMemoryBytes, Directory[] directories) {
|
||||
private MemoryItem(String key,
|
||||
String[] extensions,
|
||||
String[] prefixes,
|
||||
long usedMemoryBytes,
|
||||
DirectoryItem[] directories) {
|
||||
this.key = key;
|
||||
this.extensions = extensions;
|
||||
this.prefixes = prefixes;
|
||||
|
@ -42,7 +44,7 @@ public class DataStorageMemoryItem {
|
|||
return prefixes;
|
||||
}
|
||||
|
||||
public Directory[] getDirectories() {
|
||||
public DirectoryItem[] getDirectories() {
|
||||
return directories;
|
||||
}
|
||||
|
||||
|
@ -54,7 +56,7 @@ public class DataStorageMemoryItem {
|
|||
private String key;
|
||||
private String[] extensions;
|
||||
private String[] prefixes;
|
||||
private Directory[] directories;
|
||||
private DirectoryItem[] directories;
|
||||
private long usedMemoryBytes;
|
||||
|
||||
public DataStorageMemoryItemBuilder setKey(String key) {
|
||||
|
@ -72,7 +74,7 @@ public class DataStorageMemoryItem {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DataStorageMemoryItemBuilder setDirectories(Directory ... directories) {
|
||||
public DataStorageMemoryItemBuilder setDirectories(DirectoryItem... directories) {
|
||||
this.directories = directories;
|
||||
return this;
|
||||
}
|
||||
|
@ -82,38 +84,8 @@ public class DataStorageMemoryItem {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DataStorageMemoryItem createItem() {
|
||||
return new DataStorageMemoryItem(key, extensions, prefixes, usedMemoryBytes, directories);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Directory {
|
||||
private String absolutePath;
|
||||
private boolean goDeeper;
|
||||
private int checkingType;
|
||||
private boolean skipOther;
|
||||
|
||||
public Directory(String absolutePath, boolean goDeeper, int checkingType, boolean skipOther) {
|
||||
this.absolutePath = absolutePath;
|
||||
this.goDeeper = goDeeper;
|
||||
this.checkingType = checkingType;
|
||||
this.skipOther = skipOther;
|
||||
}
|
||||
|
||||
public String getAbsolutePath() {
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
public boolean isGoDeeper() {
|
||||
return goDeeper;
|
||||
}
|
||||
|
||||
public int getCheckingType() {
|
||||
return checkingType;
|
||||
}
|
||||
|
||||
public boolean isSkipOther() {
|
||||
return skipOther;
|
||||
public MemoryItem createItem() {
|
||||
return new MemoryItem(key, extensions, prefixes, usedMemoryBytes, directories);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package net.osmand.plus.settings.fragments;
|
||||
package net.osmand.plus.settings.datastorage.item;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
|
||||
public class DataStorageMenuItem implements Parcelable, Cloneable {
|
||||
public class StorageItem implements Parcelable, Cloneable {
|
||||
|
||||
private String key;
|
||||
private int type;
|
||||
|
@ -15,8 +15,12 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
|
|||
@IdRes
|
||||
private int iconResId;
|
||||
|
||||
private DataStorageMenuItem(String key, int type, String title, String description,
|
||||
String directory, int iconResId) {
|
||||
private StorageItem(String key,
|
||||
int type,
|
||||
String title,
|
||||
String description,
|
||||
String directory,
|
||||
int iconResId) {
|
||||
this.key = key;
|
||||
this.type = type;
|
||||
this.title = title;
|
||||
|
@ -25,7 +29,7 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
|
|||
this.iconResId = iconResId;
|
||||
}
|
||||
|
||||
private DataStorageMenuItem(Parcel in) {
|
||||
private StorageItem(Parcel in) {
|
||||
key = in.readString();
|
||||
type = in.readInt();
|
||||
title = in.readString();
|
||||
|
@ -99,16 +103,16 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
|
|||
dest.writeString(directory);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<DataStorageMenuItem> CREATOR = new Parcelable.Creator<DataStorageMenuItem>() {
|
||||
public static final Parcelable.Creator<StorageItem> CREATOR = new Parcelable.Creator<StorageItem>() {
|
||||
|
||||
@Override
|
||||
public DataStorageMenuItem createFromParcel(Parcel source) {
|
||||
return new DataStorageMenuItem(source);
|
||||
public StorageItem createFromParcel(Parcel source) {
|
||||
return new StorageItem(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataStorageMenuItem[] newArray(int size) {
|
||||
return new DataStorageMenuItem[size];
|
||||
public StorageItem[] newArray(int size) {
|
||||
return new StorageItem[size];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -151,14 +155,14 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public DataStorageMenuItem createItem() {
|
||||
return new DataStorageMenuItem(key, type, title, description, directory, iconResId);
|
||||
public StorageItem createItem() {
|
||||
return new StorageItem(key, type, title, description, directory, iconResId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return DataStorageMenuItem.builder()
|
||||
return StorageItem.builder()
|
||||
.setKey(this.key)
|
||||
.setTitle(this.title)
|
||||
.setDescription(this.description)
|
|
@ -0,0 +1,173 @@
|
|||
package net.osmand.plus.settings.datastorage.task;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.activities.OsmandActionBarActivity;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class MoveFilesTask extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
protected WeakReference<OsmandActionBarActivity> activity;
|
||||
private WeakReference<Context> context;
|
||||
private File from;
|
||||
private File to;
|
||||
protected ProgressImplementation progress;
|
||||
private Runnable runOnSuccess;
|
||||
private int movedCount;
|
||||
private long movedSize;
|
||||
private int copiedCount;
|
||||
private long copiedSize;
|
||||
private int failedCount;
|
||||
private long failedSize;
|
||||
private String exceptionMessage;
|
||||
|
||||
public MoveFilesTask(OsmandActionBarActivity activity, File from, File to) {
|
||||
this.activity = new WeakReference<>(activity);
|
||||
this.context = new WeakReference<>((Context) activity);
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public void setRunOnSuccess(Runnable runOnSuccess) {
|
||||
this.runOnSuccess = runOnSuccess;
|
||||
}
|
||||
|
||||
public int getMovedCount() {
|
||||
return movedCount;
|
||||
}
|
||||
|
||||
public int getCopiedCount() {
|
||||
return copiedCount;
|
||||
}
|
||||
|
||||
public int getFailedCount() {
|
||||
return failedCount;
|
||||
}
|
||||
|
||||
public long getMovedSize() {
|
||||
return movedSize;
|
||||
}
|
||||
|
||||
public long getCopiedSize() {
|
||||
return copiedSize;
|
||||
}
|
||||
|
||||
public long getFailedSize() {
|
||||
return failedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Context ctx = context.get();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
movedCount = 0;
|
||||
copiedCount = 0;
|
||||
failedCount = 0;
|
||||
progress = ProgressImplementation.createProgressDialog(
|
||||
ctx, ctx.getString(R.string.copying_osmand_files),
|
||||
ctx.getString(R.string.copying_osmand_files_descr, to.getPath()),
|
||||
ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
Context ctx = context.get();
|
||||
if (ctx == null) {
|
||||
return;
|
||||
}
|
||||
if (result != null) {
|
||||
if (result.booleanValue() && runOnSuccess != null) {
|
||||
runOnSuccess.run();
|
||||
} else if (!result.booleanValue()) {
|
||||
Toast.makeText(ctx, ctx.getString(R.string.shared_string_io_error) + ": " + exceptionMessage, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void movingFiles(File f, File t, int depth) throws IOException {
|
||||
Context ctx = context.get();
|
||||
if (ctx == null) {
|
||||
return;
|
||||
}
|
||||
if (depth <= 2) {
|
||||
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), -1);
|
||||
}
|
||||
if (f.isDirectory()) {
|
||||
t.mkdirs();
|
||||
File[] lf = f.listFiles();
|
||||
if (lf != null) {
|
||||
for (int i = 0; i < lf.length; i++) {
|
||||
if (lf[i] != null) {
|
||||
movingFiles(lf[i], new File(t, lf[i].getName()), depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
f.delete();
|
||||
} else if (f.isFile()) {
|
||||
if (t.exists()) {
|
||||
Algorithms.removeAllFiles(t);
|
||||
}
|
||||
boolean rnm = false;
|
||||
long fileSize = f.length();
|
||||
try {
|
||||
rnm = f.renameTo(t);
|
||||
movedCount++;
|
||||
movedSize += fileSize;
|
||||
} catch (RuntimeException e) {
|
||||
}
|
||||
if (!rnm) {
|
||||
FileInputStream fin = new FileInputStream(f);
|
||||
FileOutputStream fout = new FileOutputStream(t);
|
||||
try {
|
||||
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), (int) (f.length() / 1024));
|
||||
Algorithms.streamCopy(fin, fout, progress, 1024);
|
||||
copiedCount++;
|
||||
copiedSize += fileSize;
|
||||
} catch (IOException e) {
|
||||
failedCount++;
|
||||
failedSize += fileSize;
|
||||
} finally {
|
||||
fin.close();
|
||||
fout.close();
|
||||
}
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
if (depth <= 2) {
|
||||
progress.finishTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
to.mkdirs();
|
||||
try {
|
||||
movingFiles(from, to, 0);
|
||||
} catch (IOException e) {
|
||||
exceptionMessage = e.getMessage();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
package net.osmand.plus.settings.datastorage.task;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import net.osmand.plus.settings.datastorage.DataStorageHelper.UpdateMemoryInfoUIAdapter;
|
||||
import net.osmand.plus.settings.datastorage.item.DirectoryItem;
|
||||
import net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType;
|
||||
import net.osmand.plus.settings.datastorage.item.MemoryItem;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static net.osmand.plus.settings.datastorage.DataStorageFragment.UI_REFRESH_TIME_MS;
|
||||
import static net.osmand.util.Algorithms.objectEquals;
|
||||
|
||||
public class RefreshUsedMemoryTask extends AsyncTask<MemoryItem, Void, Void> {
|
||||
private final UpdateMemoryInfoUIAdapter uiAdapter;
|
||||
private final File root;
|
||||
private final MemoryItem otherMemoryItem;
|
||||
private final String[] directoriesToSkip;
|
||||
private final String[] filePrefixesToSkip;
|
||||
private final String tag;
|
||||
private long lastRefreshTime;
|
||||
|
||||
public RefreshUsedMemoryTask(UpdateMemoryInfoUIAdapter uiAdapter,
|
||||
MemoryItem otherMemoryItem,
|
||||
File root,
|
||||
String[] directoriesToSkip,
|
||||
String[] filePrefixesToSkip,
|
||||
String tag) {
|
||||
this.uiAdapter = uiAdapter;
|
||||
this.otherMemoryItem = otherMemoryItem;
|
||||
this.root = root;
|
||||
this.directoriesToSkip = directoriesToSkip;
|
||||
this.filePrefixesToSkip = filePrefixesToSkip;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(MemoryItem... items) {
|
||||
lastRefreshTime = System.currentTimeMillis();
|
||||
if (root.canRead()) {
|
||||
calculateMultiTypes(root, items);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void calculateMultiTypes(File rootDir,
|
||||
MemoryItem... items) {
|
||||
File[] subFiles = rootDir.listFiles();
|
||||
if (subFiles != null) {
|
||||
for (File file : subFiles) {
|
||||
if (isCancelled()) break;
|
||||
|
||||
if (file.isDirectory()) {
|
||||
if (!shouldSkipDirectory(file)) {
|
||||
processDirectory(file, items);
|
||||
}
|
||||
|
||||
} else if (file.isFile()) {
|
||||
if (!shouldSkipFile(file)) {
|
||||
processFile(rootDir, file, items);
|
||||
}
|
||||
}
|
||||
refreshUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldSkipDirectory(@NonNull File dir) {
|
||||
if (directoriesToSkip != null) {
|
||||
for (String dirToSkipPath : directoriesToSkip) {
|
||||
String dirPath = dir.getAbsolutePath();
|
||||
if (objectEquals(dirPath, dirToSkipPath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldSkipFile(@NonNull File file) {
|
||||
if (filePrefixesToSkip != null) {
|
||||
String fileName = file.getName().toLowerCase();
|
||||
for (String prefixToAvoid : filePrefixesToSkip) {
|
||||
String prefix = prefixToAvoid.toLowerCase();
|
||||
if (fileName.startsWith(prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processDirectory(@NonNull File directory,
|
||||
@NonNull MemoryItem... items) {
|
||||
String directoryPath = directory.getAbsolutePath();
|
||||
for (MemoryItem memoryItem : items) {
|
||||
DirectoryItem[] targetDirectories = memoryItem.getDirectories();
|
||||
if (targetDirectories != null) {
|
||||
for (DirectoryItem dir : targetDirectories) {
|
||||
String allowedDirPath = dir.getAbsolutePath();
|
||||
boolean isPerfectlyMatch = objectEquals(directoryPath, allowedDirPath);
|
||||
boolean isParentDirectory = !isPerfectlyMatch && (directoryPath.startsWith(allowedDirPath));
|
||||
boolean isMatchDirectory = isPerfectlyMatch || isParentDirectory;
|
||||
if (isPerfectlyMatch) {
|
||||
calculateMultiTypes(directory, items);
|
||||
return;
|
||||
} else if (isParentDirectory && dir.shouldProcessInternalDirectories()) {
|
||||
calculateMultiTypes(directory, items);
|
||||
return;
|
||||
} else if (isMatchDirectory && !dir.shouldAddUnmatchedToOtherMemory()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Current directory did not match to any type
|
||||
otherMemoryItem.addBytes(calculateFolderSize(directory));
|
||||
}
|
||||
|
||||
private void processFile(@NonNull File rootDir,
|
||||
@NonNull File file,
|
||||
@NonNull MemoryItem... items) {
|
||||
for (MemoryItem item : items) {
|
||||
DirectoryItem[] targetDirectories = item.getDirectories();
|
||||
if (targetDirectories == null) continue;
|
||||
String rootDirPath = rootDir.getAbsolutePath();
|
||||
|
||||
for (DirectoryItem targetDirectory : targetDirectories) {
|
||||
String allowedDirPath = targetDirectory.getAbsolutePath();
|
||||
boolean processInternal = targetDirectory.shouldProcessInternalDirectories();
|
||||
if (objectEquals(rootDirPath, allowedDirPath)
|
||||
|| (rootDirPath.startsWith(allowedDirPath) && processInternal)) {
|
||||
CheckingType checkingType = targetDirectory.getCheckingType();
|
||||
switch (checkingType) {
|
||||
case EXTENSIONS: {
|
||||
if (isSuitableExtension(file, item)) {
|
||||
item.addBytes(file.length());
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PREFIX: {
|
||||
if (isSuitablePrefix(file, item)) {
|
||||
item.addBytes(file.length());
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!targetDirectory.shouldAddUnmatchedToOtherMemory()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Current file did not match any type
|
||||
otherMemoryItem.addBytes(file.length());
|
||||
}
|
||||
|
||||
private boolean isSuitableExtension(@NonNull File file,
|
||||
@NonNull MemoryItem item) {
|
||||
String[] extensions = item.getExtensions();
|
||||
if (extensions != null) {
|
||||
for (String extension : extensions) {
|
||||
if (file.getAbsolutePath().endsWith(extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return extensions == null;
|
||||
}
|
||||
|
||||
private boolean isSuitablePrefix(@NonNull File file,
|
||||
@NonNull MemoryItem item) {
|
||||
String[] prefixes = item.getPrefixes();
|
||||
if (prefixes != null) {
|
||||
for (String prefix : prefixes) {
|
||||
if (file.getName().toLowerCase().startsWith(prefix.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return prefixes == null;
|
||||
}
|
||||
|
||||
private long calculateFolderSize(@NonNull File dir) {
|
||||
long bytes = 0;
|
||||
if (dir.isDirectory()) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) return 0;
|
||||
|
||||
for (File file : files) {
|
||||
if (isCancelled()) {
|
||||
break;
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
bytes += calculateFolderSize(file);
|
||||
} else if (file.isFile()) {
|
||||
bytes += file.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
super.onProgressUpdate(values);
|
||||
if (uiAdapter != null) {
|
||||
uiAdapter.onMemoryInfoUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
super.onPostExecute(aVoid);
|
||||
if (uiAdapter != null) {
|
||||
uiAdapter.onFinishUpdating(tag);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshUI() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if ((currentTime - lastRefreshTime) > UI_REFRESH_TIME_MS) {
|
||||
lastRefreshTime = currentTime;
|
||||
publishProgress();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package net.osmand.plus.settings.datastorage.task;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.ProgressImplementation;
|
||||
import net.osmand.plus.R;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ReloadDataTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private WeakReference<Context> ctx;
|
||||
protected ProgressImplementation progress;
|
||||
private OsmandApplication app;
|
||||
|
||||
public ReloadDataTask(Context ctx, OsmandApplication app) {
|
||||
this.ctx = new WeakReference<>(ctx);
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
Context c = ctx.get();
|
||||
if (c == null) {
|
||||
return;
|
||||
}
|
||||
progress = ProgressImplementation.createProgressDialog(c, c.getString(R.string.loading_data),
|
||||
c.getString(R.string.loading_data), ProgressDialog.STYLE_HORIZONTAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
try {
|
||||
if (progress.getDialog().isShowing()) {
|
||||
progress.getDialog().dismiss();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//ignored
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
app.getResourceManager().reloadIndexes(progress, new ArrayList<String>());
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -73,6 +73,7 @@ import net.osmand.plus.settings.bottomsheets.ChangeGeneralProfilesPrefBottomShee
|
|||
import net.osmand.plus.settings.bottomsheets.EditTextPreferenceBottomSheet;
|
||||
import net.osmand.plus.settings.bottomsheets.MultiSelectPreferencesBottomSheet;
|
||||
import net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet;
|
||||
import net.osmand.plus.settings.datastorage.DataStorageFragment;
|
||||
import net.osmand.plus.settings.preferences.ListPreferenceEx;
|
||||
import net.osmand.plus.settings.preferences.MultiSelectBooleanPreference;
|
||||
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
|
||||
|
|
|
@ -1,485 +0,0 @@
|
|||
package net.osmand.plus.settings.fragments;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
|
||||
import net.osmand.IndexConstants;
|
||||
import net.osmand.ValueHolder;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static net.osmand.plus.settings.fragments.DataStorageFragment.UI_REFRESH_TIME_MS;
|
||||
import static net.osmand.plus.settings.fragments.DataStorageMemoryItem.Directory;
|
||||
import static net.osmand.plus.settings.fragments.DataStorageMemoryItem.EXTENSIONS;
|
||||
import static net.osmand.plus.settings.fragments.DataStorageMemoryItem.PREFIX;
|
||||
|
||||
public class DataStorageHelper {
|
||||
public final static String INTERNAL_STORAGE = "internal_storage";
|
||||
public final static String EXTERNAL_STORAGE = "external_storage";
|
||||
public final static String SHARED_STORAGE = "shared_storage";
|
||||
public final static String MULTIUSER_STORAGE = "multiuser_storage";
|
||||
public final static String MANUALLY_SPECIFIED = "manually_specified";
|
||||
|
||||
public final static String MAPS_MEMORY = "maps_memory_used";
|
||||
public final static String SRTM_AND_HILLSHADE_MEMORY = "contour_lines_and_hillshade_memory";
|
||||
public final static String TRACKS_MEMORY = "tracks_memory_used";
|
||||
public final static String NOTES_MEMORY = "notes_memory_used";
|
||||
public final static String TILES_MEMORY = "tiles_memory_used";
|
||||
public final static String OTHER_MEMORY = "other_memory_used";
|
||||
|
||||
private ArrayList<DataStorageMenuItem> menuItems = new ArrayList<>();
|
||||
private DataStorageMenuItem currentDataStorage;
|
||||
private DataStorageMenuItem manuallySpecified;
|
||||
|
||||
private ArrayList<DataStorageMemoryItem> memoryItems = new ArrayList<>();
|
||||
private DataStorageMemoryItem mapsMemory;
|
||||
private DataStorageMemoryItem srtmAndHillshadeMemory;
|
||||
private DataStorageMemoryItem tracksMemory;
|
||||
private DataStorageMemoryItem notesMemory;
|
||||
private DataStorageMemoryItem tilesMemory;
|
||||
private DataStorageMemoryItem otherMemory;
|
||||
|
||||
private int currentStorageType;
|
||||
private String currentStoragePath;
|
||||
|
||||
public DataStorageHelper(OsmandApplication app) {
|
||||
prepareData(app);
|
||||
}
|
||||
|
||||
private void prepareData(OsmandApplication app) {
|
||||
|
||||
if (app == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
OsmandSettings settings = app.getSettings();
|
||||
|
||||
if (settings.getExternalStorageDirectoryTypeV19() >= 0) {
|
||||
currentStorageType = settings.getExternalStorageDirectoryTypeV19();
|
||||
} else {
|
||||
ValueHolder<Integer> vh = new ValueHolder<Integer>();
|
||||
if (vh.value != null && vh.value >= 0) {
|
||||
currentStorageType = vh.value;
|
||||
} else {
|
||||
currentStorageType = 0;
|
||||
}
|
||||
}
|
||||
currentStoragePath = settings.getExternalStorageDirectory().getAbsolutePath();
|
||||
|
||||
String path;
|
||||
File dir;
|
||||
int iconId;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
|
||||
//internal storage
|
||||
path = settings.getInternalAppPath().getAbsolutePath();
|
||||
dir = new File(path);
|
||||
iconId = R.drawable.ic_action_phone;
|
||||
|
||||
DataStorageMenuItem internalStorageItem = DataStorageMenuItem.builder()
|
||||
.setKey(INTERNAL_STORAGE)
|
||||
.setTitle(app.getString(R.string.storage_directory_internal_app))
|
||||
.setDirectory(path)
|
||||
.setDescription(app.getString(R.string.internal_app_storage_description))
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_INTERNAL_FILE)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(internalStorageItem);
|
||||
|
||||
//shared_storage
|
||||
dir = settings.getDefaultInternalStorage();
|
||||
path = dir.getAbsolutePath();
|
||||
iconId = R.drawable.ic_action_phone;
|
||||
|
||||
DataStorageMenuItem sharedStorageItem = DataStorageMenuItem.builder()
|
||||
.setKey(SHARED_STORAGE)
|
||||
.setTitle(app.getString(R.string.storage_directory_shared))
|
||||
.setDirectory(path)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_DEFAULT)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(sharedStorageItem);
|
||||
|
||||
//external storage
|
||||
File[] externals = app.getExternalFilesDirs(null);
|
||||
if (externals != null) {
|
||||
int i = 0;
|
||||
for (File external : externals) {
|
||||
if (external != null) {
|
||||
++i;
|
||||
dir = external;
|
||||
path = dir.getAbsolutePath();
|
||||
iconId = getIconForStorageType(dir);
|
||||
DataStorageMenuItem externalStorageItem = DataStorageMenuItem.builder()
|
||||
.setKey(EXTERNAL_STORAGE + i)
|
||||
.setTitle(app.getString(R.string.storage_directory_external) + " " + i)
|
||||
.setDirectory(path)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_EXTERNAL_FILE)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(externalStorageItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//multi user storage
|
||||
File[] obbDirs = app.getObbDirs();
|
||||
if (obbDirs != null) {
|
||||
int i = 0;
|
||||
for (File obb : obbDirs) {
|
||||
if (obb != null) {
|
||||
++i;
|
||||
dir = obb;
|
||||
path = dir.getAbsolutePath();
|
||||
iconId = getIconForStorageType(dir);
|
||||
DataStorageMenuItem multiuserStorageItem = DataStorageMenuItem.builder()
|
||||
.setKey(MULTIUSER_STORAGE + i)
|
||||
.setTitle(app.getString(R.string.storage_directory_multiuser) + " " + i)
|
||||
.setDirectory(path)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_OBB)
|
||||
.setIconResId(iconId)
|
||||
.createItem();
|
||||
addItem(multiuserStorageItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//manually specified storage
|
||||
manuallySpecified = DataStorageMenuItem.builder()
|
||||
.setKey(MANUALLY_SPECIFIED)
|
||||
.setTitle(app.getString(R.string.storage_directory_manual))
|
||||
.setDirectory(currentStoragePath)
|
||||
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_SPECIFIED)
|
||||
.setIconResId(R.drawable.ic_action_folder)
|
||||
.createItem();
|
||||
menuItems.add(manuallySpecified);
|
||||
|
||||
if (currentDataStorage == null) {
|
||||
currentDataStorage = manuallySpecified;
|
||||
}
|
||||
|
||||
initMemoryUsed(app);
|
||||
}
|
||||
|
||||
private void initMemoryUsed(OsmandApplication app) {
|
||||
mapsMemory = DataStorageMemoryItem.builder()
|
||||
.setKey(MAPS_MEMORY)
|
||||
.setExtensions(IndexConstants.BINARY_MAP_INDEX_EXT)
|
||||
.setDirectories(
|
||||
new Directory(app.getAppPath(IndexConstants.MAPS_PATH).getAbsolutePath(), false, EXTENSIONS, false),
|
||||
new Directory(app.getAppPath(IndexConstants.ROADS_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
|
||||
new Directory(app.getAppPath(IndexConstants.WIKI_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
|
||||
new Directory(app.getAppPath(IndexConstants.WIKIVOYAGE_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
|
||||
new Directory(app.getAppPath(IndexConstants.BACKUP_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
|
||||
.createItem();
|
||||
memoryItems.add(mapsMemory);
|
||||
|
||||
srtmAndHillshadeMemory = DataStorageMemoryItem.builder()
|
||||
.setKey(SRTM_AND_HILLSHADE_MEMORY)
|
||||
.setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
|
||||
.setDirectories(
|
||||
new Directory(app.getAppPath(IndexConstants.SRTM_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
|
||||
new Directory(app.getAppPath(IndexConstants.TILES_INDEX_DIR).getAbsolutePath(), false, PREFIX, true))
|
||||
.setPrefixes("Hillshade")
|
||||
.createItem();
|
||||
memoryItems.add(srtmAndHillshadeMemory);
|
||||
|
||||
tracksMemory = DataStorageMemoryItem.builder()
|
||||
.setKey(TRACKS_MEMORY)
|
||||
// .setExtensions(IndexConstants.GPX_FILE_EXT, ".gpx.bz2")
|
||||
.setDirectories(
|
||||
new Directory(app.getAppPath(IndexConstants.GPX_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
|
||||
.createItem();
|
||||
memoryItems.add(tracksMemory);
|
||||
|
||||
notesMemory = DataStorageMemoryItem.builder()
|
||||
.setKey(NOTES_MEMORY)
|
||||
// .setExtensions("")
|
||||
.setDirectories(
|
||||
new Directory(app.getAppPath(IndexConstants.AV_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
|
||||
.createItem();
|
||||
memoryItems.add(notesMemory);
|
||||
|
||||
tilesMemory = DataStorageMemoryItem.builder()
|
||||
.setKey(TILES_MEMORY)
|
||||
// .setExtensions("")
|
||||
.setDirectories(
|
||||
new Directory(app.getAppPath(IndexConstants.TILES_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
|
||||
.createItem();
|
||||
memoryItems.add(tilesMemory);
|
||||
|
||||
otherMemory = DataStorageMemoryItem.builder()
|
||||
.setKey(OTHER_MEMORY)
|
||||
.createItem();
|
||||
memoryItems.add(otherMemory);
|
||||
}
|
||||
|
||||
public ArrayList<DataStorageMenuItem> getStorageItems() {
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
private int getIconForStorageType(File dir) {
|
||||
return R.drawable.ic_action_folder;
|
||||
}
|
||||
|
||||
public DataStorageMenuItem getCurrentStorage() {
|
||||
return currentDataStorage;
|
||||
}
|
||||
|
||||
private void addItem(DataStorageMenuItem item) {
|
||||
if (currentStorageType == item.getType() && currentStoragePath.equals(item.getDirectory())) {
|
||||
currentDataStorage = item;
|
||||
}
|
||||
menuItems.add(item);
|
||||
}
|
||||
|
||||
public DataStorageMenuItem getManuallySpecified() {
|
||||
return manuallySpecified;
|
||||
}
|
||||
|
||||
public DataStorageMenuItem getStorage(String key) {
|
||||
if (menuItems != null && key != null) {
|
||||
for (DataStorageMenuItem menuItem : menuItems) {
|
||||
if (key.equals(menuItem.getKey())) {
|
||||
return menuItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCurrentType() {
|
||||
return currentStorageType;
|
||||
}
|
||||
|
||||
public String getCurrentPath() {
|
||||
return currentStoragePath;
|
||||
}
|
||||
|
||||
public ArrayList<DataStorageMemoryItem> getMemoryInfoItems() {
|
||||
return memoryItems;
|
||||
}
|
||||
|
||||
public RefreshMemoryUsedInfo calculateMemoryUsedInfo(UpdateMemoryInfoUIAdapter listener) {
|
||||
File rootDir = new File(currentStoragePath);
|
||||
RefreshMemoryUsedInfo task = new RefreshMemoryUsedInfo(listener, otherMemory, rootDir, null, null, OTHER_MEMORY);
|
||||
task.execute(mapsMemory, srtmAndHillshadeMemory, tracksMemory, notesMemory);
|
||||
return task;
|
||||
}
|
||||
|
||||
public RefreshMemoryUsedInfo calculateTilesMemoryUsed(UpdateMemoryInfoUIAdapter listener) {
|
||||
File rootDir = new File(tilesMemory.getDirectories()[0].getAbsolutePath());
|
||||
RefreshMemoryUsedInfo task = new RefreshMemoryUsedInfo(listener, otherMemory, rootDir, null, srtmAndHillshadeMemory.getPrefixes(), TILES_MEMORY);
|
||||
task.execute(tilesMemory);
|
||||
return task;
|
||||
}
|
||||
|
||||
public static class RefreshMemoryUsedInfo extends AsyncTask<DataStorageMemoryItem, Void, Void> {
|
||||
private UpdateMemoryInfoUIAdapter listener;
|
||||
private File rootDir;
|
||||
private DataStorageMemoryItem otherMemory;
|
||||
private String[] directoriesToAvoid;
|
||||
private String[] prefixesToAvoid;
|
||||
private String taskKey;
|
||||
private long lastRefreshTime;
|
||||
|
||||
public RefreshMemoryUsedInfo(UpdateMemoryInfoUIAdapter listener, DataStorageMemoryItem otherMemory, File rootDir, String[] directoriesToAvoid, String[] prefixesToAvoid, String taskKey) {
|
||||
this.listener = listener;
|
||||
this.otherMemory = otherMemory;
|
||||
this.rootDir = rootDir;
|
||||
this.directoriesToAvoid = directoriesToAvoid;
|
||||
this.prefixesToAvoid = prefixesToAvoid;
|
||||
this.taskKey = taskKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(DataStorageMemoryItem... items) {
|
||||
lastRefreshTime = System.currentTimeMillis();
|
||||
if (rootDir.canRead()) {
|
||||
calculateMultiTypes(rootDir, items);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void calculateMultiTypes(File rootDir, DataStorageMemoryItem... items) {
|
||||
File[] subFiles = rootDir.listFiles();
|
||||
|
||||
for (File file : subFiles) {
|
||||
if (isCancelled()) {
|
||||
break;
|
||||
}
|
||||
nextFile : {
|
||||
if (file.isDirectory()) {
|
||||
//check current directory should be avoid
|
||||
if (directoriesToAvoid != null) {
|
||||
for (String directoryToAvoid : directoriesToAvoid) {
|
||||
if (file.getAbsolutePath().equals(directoryToAvoid)) {
|
||||
break nextFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
//check current directory matched items type
|
||||
for (DataStorageMemoryItem item : items) {
|
||||
Directory[] directories = item.getDirectories();
|
||||
if (directories == null) {
|
||||
continue;
|
||||
}
|
||||
for (Directory dir : directories) {
|
||||
if (file.getAbsolutePath().equals(dir.getAbsolutePath())
|
||||
|| (file.getAbsolutePath().startsWith(dir.getAbsolutePath()))) {
|
||||
if (dir.isGoDeeper()) {
|
||||
calculateMultiTypes(file, items);
|
||||
break nextFile;
|
||||
} else if (dir.isSkipOther()) {
|
||||
break nextFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//current directory did not match to any type
|
||||
otherMemory.addBytes(getDirectorySize(file));
|
||||
} else if (file.isFile()) {
|
||||
//check current file should be avoid
|
||||
if (prefixesToAvoid != null) {
|
||||
for (String prefixToAvoid : prefixesToAvoid) {
|
||||
if (file.getName().toLowerCase().startsWith(prefixToAvoid.toLowerCase())) {
|
||||
break nextFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
//check current file matched items type
|
||||
for (DataStorageMemoryItem item : items) {
|
||||
Directory[] directories = item.getDirectories();
|
||||
if (directories == null) {
|
||||
continue;
|
||||
}
|
||||
for (Directory dir : directories) {
|
||||
if (rootDir.getAbsolutePath().equals(dir.getAbsolutePath())
|
||||
|| (rootDir.getAbsolutePath().startsWith(dir.getAbsolutePath()) && dir.isGoDeeper())) {
|
||||
int checkingType = dir.getCheckingType();
|
||||
switch (checkingType) {
|
||||
case EXTENSIONS : {
|
||||
String[] extensions = item.getExtensions();
|
||||
if (extensions != null) {
|
||||
for (String extension : extensions) {
|
||||
if (file.getAbsolutePath().endsWith(extension)) {
|
||||
item.addBytes(file.length());
|
||||
break nextFile;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item.addBytes(file.length());
|
||||
break nextFile;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
case PREFIX : {
|
||||
String[] prefixes = item.getPrefixes();
|
||||
if (prefixes != null) {
|
||||
for (String prefix : prefixes) {
|
||||
if (file.getName().toLowerCase().startsWith(prefix.toLowerCase())) {
|
||||
item.addBytes(file.length());
|
||||
break nextFile;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
item.addBytes(file.length());
|
||||
break nextFile;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
}
|
||||
if (dir.isSkipOther()) {
|
||||
break nextFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//current file did not match any type
|
||||
otherMemory.addBytes(file.length());
|
||||
}
|
||||
}
|
||||
refreshUI();
|
||||
}
|
||||
}
|
||||
|
||||
private long getDirectorySize(File dir) {
|
||||
long bytes = 0;
|
||||
if (dir.isDirectory()) {
|
||||
File[] files = dir.listFiles();
|
||||
for (File file : files) {
|
||||
if (isCancelled()) {
|
||||
break;
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
bytes += getDirectorySize(file);
|
||||
} else if (file.isFile()) {
|
||||
bytes += file.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
super.onProgressUpdate(values);
|
||||
if (listener != null) {
|
||||
listener.onMemoryInfoUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
super.onPostExecute(aVoid);
|
||||
if (listener != null) {
|
||||
listener.onFinishUpdating(taskKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshUI() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if ((currentTime - lastRefreshTime) > UI_REFRESH_TIME_MS) {
|
||||
lastRefreshTime = currentTime;
|
||||
publishProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long getTotalUsedBytes() {
|
||||
long total = 0;
|
||||
if (memoryItems != null && memoryItems.size() > 0) {
|
||||
for (DataStorageMemoryItem mi : memoryItems) {
|
||||
total += mi.getUsedMemoryBytes();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String getFormattedMemoryInfo(long bytes, String[] formatStrings) {
|
||||
int type = 0;
|
||||
double memory = (double) bytes / 1024;
|
||||
while (memory > 1024 && type < formatStrings.length) {
|
||||
++type;
|
||||
memory = memory / 1024;
|
||||
}
|
||||
String formattedUsed = new DecimalFormat("#.##").format(memory);
|
||||
return String.format(formatStrings[type], formattedUsed);
|
||||
}
|
||||
|
||||
public interface UpdateMemoryInfoUIAdapter {
|
||||
|
||||
void onMemoryInfoUpdate();
|
||||
|
||||
void onFinishUpdating(String taskKey);
|
||||
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ import net.osmand.plus.profiles.SelectProfileBottomSheet.DialogMode;
|
|||
import net.osmand.plus.profiles.SelectProfileBottomSheet.OnSelectProfileCallback;
|
||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.settings.datastorage.DataStorageHelper;
|
||||
import net.osmand.plus.settings.datastorage.item.StorageItem;
|
||||
import net.osmand.plus.settings.preferences.ListPreferenceEx;
|
||||
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
|
||||
|
||||
|
@ -181,7 +183,7 @@ public class GlobalSettingsFragment extends BaseSettingsFragment
|
|||
externalStorageDir.setIcon(getActiveIcon(R.drawable.ic_action_folder));
|
||||
|
||||
DataStorageHelper holder = new DataStorageHelper(app);
|
||||
DataStorageMenuItem currentStorage = holder.getCurrentStorage();
|
||||
StorageItem currentStorage = holder.getCurrentStorage();
|
||||
long totalUsed = app.getSettings().OSMAND_USAGE_SPACE.get();
|
||||
if (totalUsed > 0) {
|
||||
String[] usedMemoryFormats = new String[] {
|
||||
|
|
Loading…
Reference in a new issue