/* * Copyright 2014 Yaroslav Mytkalyk * 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.docd.purefm.utils; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.math.BigInteger; import java.util.Comparator; import java.util.List; import org.apache.commons.io.FileExistsException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.docd.purefm.Environment; import com.docd.purefm.R; import com.docd.purefm.commandline.CommandCopyRecursively; import com.docd.purefm.commandline.CommandLine; import com.docd.purefm.commandline.CommandMove; import com.docd.purefm.commandline.CommandRemove; import com.docd.purefm.commandline.CommandStat; import com.docd.purefm.commandline.ShellHolder; import com.docd.purefm.file.GenericFile; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.text.InputFilter; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; public final class PFMFileUtils { private PFMFileUtils() { } public static final class FileNameFilter implements InputFilter { public static final int MAX_FILENAME_LENGTH = 255; private static final String FILENAME_PATTERN = "\\\\|/|:|\\*|\\?|\"|<|>|\r|\n"; @Nullable @Override public CharSequence filter(final CharSequence source, final int start, final int end, final Spanned dest, final int dstart, final int dend) { if (source.length() == 0) { //nothing to filter return null; } final CharSequence sourceSubSequence = source.subSequence(start, end); final String sourceSubSequenceString = sourceSubSequence.toString(); final String sourceProcessed = sourceSubSequenceString.replaceAll(FILENAME_PATTERN, ""); if (sourceSubSequenceString.equals(sourceProcessed)) { // nothing filtered return null; } if (source instanceof Spanned) { // copy spans from original source final Spannable processed = new SpannableString(sourceProcessed); TextUtils.copySpansFrom((Spanned) source, start, processed.length(), null, processed, 0); return processed; } return sourceProcessed; } } /** * Returns canonical path or absolute path if failed * * @param file File to get full path * @return canonical path or absolute path if failed */ @NonNull public static String fullPath(@NonNull final GenericFile file) { try { return file.getCanonicalPath(); } catch (IOException e) { return file.getAbsolutePath(); } } /** * Returns canonical path or absolute path if failed * * @param file File to get full path * @return canonical path or absolute path if failed */ @NonNull public static String fullPath(@NonNull final File file) { try { return file.getCanonicalPath(); } catch (IOException e) { return file.getAbsolutePath(); } } @NonNull public static String byteCountToDisplaySize(@NonNull final BigInteger size) { String displaySize; if (size.divide(FileUtils.ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(FileUtils.ONE_GB_BI)) + " GiB"; } else if (size.divide(FileUtils.ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(FileUtils.ONE_MB_BI)) + " MiB"; } else if (size.divide(FileUtils.ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(FileUtils.ONE_KB_BI)) + " KiB"; } else { displaySize = String.valueOf(size) + " B"; } return displaySize; } @Nullable public static String resolveFileSystem(@NonNull final GenericFile file) { final String path = PFMFileUtils.fullPath(file); return resolveFileSystem(FilenameUtils.getFullPathNoEndSeparator(path)); } @Nullable public static String resolveFileSystem(@NonNull final String path) { for (final StorageHelper.Volume v : Environment.getVolumes()) { if (path.startsWith(v.file.getAbsolutePath())) { return v.fileSystem; } } if (!ShellHolder.getInstance().hasShell()) { Log.w("resolveFileSystem()", "no shell, aborting"); return null; } final List<String> fsTypeResult = CommandLine.executeForResult(new CommandStat(path)); return fsTypeResult == null || fsTypeResult.isEmpty() ? null : fsTypeResult.get(0); } public static void openFileInExternalApp(@NonNull final Context context, @NonNull final File target) { final String mime = MimeTypes.getMimeType(target); if (mime != null) { final Intent i = new Intent(Intent.ACTION_VIEW); i.setDataAndType(Uri.fromFile(target), mime); final PackageManager packageManager = context.getPackageManager(); if (packageManager == null) { throw new IllegalArgumentException("No PackageManager for context"); } if (packageManager.queryIntentActivities(i, 0).isEmpty()) { Toast.makeText(context, R.string.no_apps_to_open, Toast.LENGTH_SHORT).show(); return; } try { context.startActivity(i); } catch (Exception e) { Toast.makeText(context, context.getString(R.string.could_not_open_file_) + e.getMessage(), Toast.LENGTH_SHORT).show(); } } } public static void moveFile(@NonNull final GenericFile source, @NonNull final GenericFile target, final boolean useCommandLine) throws IOException { if (useCommandLine) { if (target.exists()) { throw new FileExistsException("Target exists"); } final boolean result = CommandLine.execute(new CommandMove(source, target)); if (!result) { throw new IOException("Move failed"); } } else { FileUtils.moveFile(source.toFile(), target.toFile()); } } public static void copyFile(@NonNull final GenericFile source, @NonNull final GenericFile target, final boolean useCommandLine) throws IOException { if (useCommandLine) { final boolean result = CommandLine.execute(new CommandCopyRecursively(source, target)); if (!result) { throw new IOException("Move failed"); } } else { FileUtils.copyFile(source.toFile(), target.toFile()); } } public static void copyFileToDirectory(@NonNull final GenericFile source, @NonNull final GenericFile target, final boolean useCommandLine) throws IOException { if (useCommandLine) { if (!target.exists()) { throw new FileNotFoundException("Target doesn't exist"); } if (!target.isDirectory()) { throw new IllegalArgumentException("Target is not a directory"); } final boolean result = CommandLine.execute(new CommandCopyRecursively(source, target)); if (!result) { throw new IOException("Move failed"); } } else { FileUtils.copyFileToDirectory(source.toFile(), target.toFile()); } } public static void moveDirectory(@NonNull final GenericFile source, @NonNull final GenericFile target, final boolean useCommandLine) throws IOException { if (useCommandLine) { if (target.exists()) { throw new FileExistsException("Target exists"); } final boolean result = CommandLine.execute(new CommandMove(source, target)); if (!result) { throw new IOException("Move failed"); } } else { FileUtils.moveDirectory(source.toFile(), target.toFile()); } } public static void moveToDirectory(@NonNull final GenericFile source, @NonNull final GenericFile target, final boolean useCommandLine, final boolean createDestDir) throws IOException { if (useCommandLine) { if (!source.exists()) { throw new FileNotFoundException("Source '" + source + "' does not exist"); } if (target.exists()) { if (!target.isDirectory()) { throw new IOException("Target is not a directory"); } } else { if (createDestDir) { if (!target.mkdirs()) { throw new IOException("Failed to create target directory"); } } else { throw new FileNotFoundException("Target directory doesn't exist"); } } final boolean result = CommandLine.execute(new CommandMove(source, target)); if (!result) { throw new IOException("Moving failed"); } } else { FileUtils.moveToDirectory(source.toFile(), target.toFile(), createDestDir); } } public static void copyDirectory(@NonNull final GenericFile source, @NonNull final GenericFile target, final boolean useCommandLine) throws IOException { if (useCommandLine) { if (!source.exists()) { throw new FileNotFoundException("Source '" + source + "' does not exist"); } if (!source.isDirectory()) { throw new IOException("Source '" + source + "' exists but is not a directory"); } if (source.getCanonicalPath().equals(target.getCanonicalPath())) { throw new IOException("Source '" + source + "' and destination '" + target + "' are the same"); } final boolean result = CommandLine.execute(new CommandCopyRecursively(source, target)); if (!result) { throw new IOException("Copying failed"); } } else { FileUtils.copyDirectory(source.toFile(), target.toFile()); } } public static void copyDirectoryToDirectory(@NonNull final GenericFile source, @NonNull final GenericFile target, final boolean useCommandLine) throws IOException { if (useCommandLine) { if (!source.exists()) { throw new FileNotFoundException("Source '" + source + "' does not exist"); } if (!source.isDirectory()) { throw new IOException("Source '" + source + "' exists but is not a directory"); } if (source.getCanonicalPath().equals(target.getCanonicalPath())) { throw new IOException("Source '" + source + "' and destination '" + target + "' are the same"); } if (!target.exists()) { throw new FileNotFoundException("Target dir does not exist"); } if (!target.isDirectory()) { throw new IOException("Target is not a directory"); } final boolean result = CommandLine.execute(new CommandCopyRecursively(source, target)); if (!result) { throw new IOException("Copying failed"); } } else { FileUtils.copyDirectoryToDirectory(source.toFile(), target.toFile()); } } public static void forceDelete(@NonNull final GenericFile file, final boolean useCommandLine) throws IOException { if (useCommandLine) { if (!file.exists()) { throw new FileNotFoundException("File does not exist: " + file); } final boolean result = CommandLine.execute(new CommandRemove(file.toFile())); if (!result) { throw new IOException("Removing failed"); } } else { FileUtils.forceDelete(file.toFile()); } } public static final class NameComparator implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { if (a.isDirectory() && b.isDirectory()) { return String.CASE_INSENSITIVE_ORDER.compare(a.getName(), b.getName()); } if (a.isDirectory()) { return -1; } if (b.isDirectory()) { return 1; } return a.getName().compareTo(b.getName()); } } public static final class NameComparatorReverse implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { if (a.isDirectory() && b.isDirectory()) { final int res = String.CASE_INSENSITIVE_ORDER.compare(a.getName(), b.getName()); if (res == 0) { return 0; } if (res < 0) { return 1; } return -1; } if (a.isDirectory()) { return -1; } if (b.isDirectory()) { return 1; } final int res = a.getName().compareTo(b.getName()); if (res == 0) { return 0; } if (res < 0) { return 1; } return -1; } } public static final class DateComparatorAsc implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { final long date_a = a.lastModified(); final long date_b = b.lastModified(); if (date_a == date_b) { return 0; } if (date_a < date_b) { return -1; } return 1; } } public static final class DateComparatorDesc implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { final long date_a = a.lastModified(); final long date_b = b.lastModified(); if (date_a == date_b) { return 0; } if (date_a < date_b) { return 1; } return -1; } } public static final class SizeComparatorAsc implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { if (a.isDirectory() && b.isDirectory()) { return a.getName().compareTo(b.getName()); } if (a.isDirectory()) { return -1; } if (b.isDirectory()) { return 1; } final long len_a = a.length(); final long len_b = b.length(); if (len_a == len_b) { return a.getName().compareTo(b.getName()); } if (len_a < len_b) { return -1; } return 1; } } public static final class SizeComparatorDesc implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { if (a.isDirectory() && b.isDirectory()) { return a.getName().compareTo(b.getName()); } if (a.isDirectory()) { return 1; } if (b.isDirectory()) { return -1; } final long len_a = a.length(); final long len_b = b.length(); if (len_a == len_b) { return a.getName().compareTo(b.getName()); } if (len_a < len_b) { return 1; } return -1; } } public static final class TypeComparator implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { if (a.isDirectory() && b.isDirectory()) { return a.getName().compareTo(b.getName()); } if (a.isDirectory()) { return -1; } if (b.isDirectory()) { return 1; } final String ext_a = FilenameUtils.getExtension(a.getName()); final String ext_b = FilenameUtils.getExtension(b.getName()); if (ext_a.isEmpty() && ext_b.isEmpty()) { return a.getName().compareTo(b.getName()); } if (ext_a.isEmpty()) { return -1; } if (ext_b.isEmpty()) { return 1; } final int res = ext_a.compareTo(ext_b); if (res == 0) { return a.getName().compareTo(b.getName()); } return res; } } public static final class TypeComparatorReverse implements Comparator<GenericFile> { @Override public int compare(final GenericFile a, final GenericFile b) { if (a.isDirectory() && b.isDirectory()) { return a.getName().compareTo(b.getName()); } if (a.isDirectory()) { return -1; } if (b.isDirectory()) { return 1; } final String ext_a = FilenameUtils.getExtension(a.getName()); final String ext_b = FilenameUtils.getExtension(b.getName()); if (ext_a.isEmpty() && ext_b.isEmpty()) { return a.getName().compareTo(b.getName()); } if (ext_a.isEmpty()) { return 1; } if (ext_b.isEmpty()) { return -1; } final int res = ext_a.compareTo(ext_b); if (res == 0) { return a.getName().compareTo(b.getName()); } return res; } } }