PlayerAndroid/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java

268 lines
9.0 KiB
Java

/*
* Copyright (c) 2019 Hemanth Savarala.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*/
package code.name.monkey.retromusic.util;
import android.content.Context;
import android.database.Cursor;
import android.os.Environment;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import code.name.monkey.retromusic.loaders.SongLoader;
import code.name.monkey.retromusic.loaders.SortedCursor;
import code.name.monkey.retromusic.model.Song;
import io.reactivex.Observable;
public final class FileUtil {
private FileUtil() {
}
public static byte[] readBytes(InputStream stream) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int count;
while ((count = stream.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
stream.close();
return baos.toByteArray();
}
@NonNull
public static Observable<ArrayList<Song>> matchFilesWithMediaStore(@NonNull Context context,
@Nullable List<File> files) {
return SongLoader.INSTANCE.getSongs(makeSongCursor(context, files));
}
public static String safeGetCanonicalPath(File file) {
try {
return file.getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsolutePath();
}
}
@Nullable
public static SortedCursor makeSongCursor(@NonNull final Context context,
@Nullable final List<File> files) {
String selection = null;
String[] paths = null;
if (files != null) {
paths = toPathArray(files);
if (files.size() > 0
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
selection =
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
}
}
Cursor songCursor = SongLoader.INSTANCE.makeSongCursor(context, selection, selection == null ? null : paths);
return songCursor == null ? null
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
}
private static String makePlaceholders(int len) {
StringBuilder sb = new StringBuilder(len * 2 - 1);
sb.append("?");
for (int i = 1; i < len; i++) {
sb.append(",?");
}
return sb.toString();
}
@Nullable
private static String[] toPathArray(@Nullable List<File> files) {
if (files != null) {
String[] paths = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
/*try {
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
} catch (IOException e) {
e.printStackTrace();
paths[i] = files.get(i).getPath();
}*/
paths[i] = safeGetCanonicalPath(files.get(i));
}
return paths;
}
return null;
}
@NonNull
public static List<File> listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> fileList = new LinkedList<>();
File[] found = directory.listFiles(fileFilter);
if (found != null) {
Collections.addAll(fileList, found);
}
return fileList;
}
@NonNull
public static List<File> listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) {
List<File> files = new LinkedList<>();
internalListFilesDeep(files, directory, fileFilter);
return files;
}
@NonNull
public static List<File> listFilesDeep(@NonNull Collection<File> files,
@Nullable FileFilter fileFilter) {
List<File> resFiles = new LinkedList<>();
for (File file : files) {
if (file.isDirectory()) {
internalListFilesDeep(resFiles, file, fileFilter);
} else if (fileFilter == null || fileFilter.accept(file)) {
resFiles.add(file);
}
}
return resFiles;
}
private static void internalListFilesDeep(@NonNull Collection<File> files,
@NonNull File directory, @Nullable FileFilter fileFilter) {
File[] found = directory.listFiles(fileFilter);
if (found != null) {
for (File file : found) {
if (file.isDirectory()) {
internalListFilesDeep(files, file, fileFilter);
} else {
files.add(file);
}
}
}
}
public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) {
if (mimeType == null || mimeType.equals("*/*")) {
return true;
} else {
// get the file mime type
String filename = file.toURI().toString();
int dotPos = filename.lastIndexOf('.');
if (dotPos == -1) {
return false;
}
String fileExtension = filename.substring(dotPos + 1).toLowerCase();
String fileType = mimeTypeMap.getMimeTypeFromExtension(fileExtension);
if (fileType == null) {
return false;
}
// check the 'type/subtype' pattern
if (fileType.equals(mimeType)) {
return true;
}
// check the 'type/*' pattern
int mimeTypeDelimiter = mimeType.lastIndexOf('/');
if (mimeTypeDelimiter == -1) {
return false;
}
String mimeTypeMainType = mimeType.substring(0, mimeTypeDelimiter);
String mimeTypeSubtype = mimeType.substring(mimeTypeDelimiter + 1);
if (!mimeTypeSubtype.equals("*")) {
return false;
}
int fileTypeDelimiter = fileType.lastIndexOf('/');
if (fileTypeDelimiter == -1) {
return false;
}
String fileTypeMainType = fileType.substring(0, fileTypeDelimiter);
if (fileTypeMainType.equals(mimeTypeMainType)) {
return true;
}
return fileTypeMainType.equals(mimeTypeMainType);
}
}
public static String stripExtension(String str) {
if (str == null) {
return null;
}
int pos = str.lastIndexOf('.');
if (pos == -1) {
return str;
}
return str.substring(0, pos);
}
public static String readFromStream(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(line);
}
reader.close();
return sb.toString();
}
public static String read(File file) throws Exception {
FileInputStream fin = new FileInputStream(file);
String ret = readFromStream(fin);
fin.close();
return ret;
}
public static boolean isExternalMemoryAvailable() {
Boolean isSDPresent = Environment.getExternalStorageState()
.equals(android.os.Environment.MEDIA_MOUNTED);
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
if (isSDSupportedDevice && isSDPresent) {
// yes SD-card is present
return true;
} else {
return false;
// Sorry
}
}
public static File safeGetCanonicalFile(File file) {
try {
return file.getCanonicalFile();
} catch (IOException e) {
e.printStackTrace();
return file.getAbsoluteFile();
}
}
}