package com.simplecity.amp_library.tagger;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.support.v4.provider.DocumentFile;
import android.util.Log;
import com.afollestad.materialdialogs.MaterialDialog;
import com.crashlytics.android.Crashlytics;
import com.simplecity.amp_library.R;
import com.simplecity.amp_library.ShuttleApplication;
import com.simplecity.amp_library.utils.DialogUtils;
import com.simplecity.amp_library.utils.SettingsManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
public class TaggerUtils {
private static final String TAG = "TaggerUtils";
//This class is never instantiated
private TaggerUtils() {
}
/**
* Checks the passed in paths to see whether the file at the given path is available in our
* document tree. If it is, and we have write permission, the document file is added to the
* passed in list of document files.
*
* @param documentFiles a list of document files to be populated
* @param paths a list of paths
* @return true if we have permission for all files at the passed in paths
*/
static boolean hasDocumentTreePermission(List<DocumentFile> documentFiles, List<String> paths) {
boolean hasDocumentTreePermission = false;
String treeUri = SettingsManager.getInstance().getDocumentTreeUri();
if (treeUri == null) {
//We don't have any document tree at all - so we're not going to have permission for any files.
return false;
}
//Find the file in the document tree. If it's not there, or it doesn't have permission,
//we're satisfied we don't have permission.
for (String path : paths) {
File file = new File(path);
DocumentFile documentFile = getDocumentFile(Uri.parse(treeUri), file);
if (documentFile != null) {
hasDocumentTreePermission = documentFile.canWrite();
}
if (hasDocumentTreePermission) {
documentFiles.add(documentFile);
} else {
documentFiles.clear();
break;
}
}
return hasDocumentTreePermission;
}
static DocumentFile getDocumentFile(Uri treeUri, final File file) {
String baseFolder = getExtSdCardFolder(file);
if (baseFolder == null) {
return null;
}
if (treeUri == null) {
return null;
}
String relativePath;
try {
String fullPath = file.getCanonicalPath();
relativePath = fullPath.substring(baseFolder.length() + 1);
} catch (IOException e) {
return null;
}
// start with root of SD card and then parse through document tree.
DocumentFile document = DocumentFile.fromTreeUri(ShuttleApplication.getInstance(), treeUri);
String[] parts = relativePath.split("\\/");
for (String part : parts) {
DocumentFile nextDocument = document.findFile(part);
if (nextDocument != null) {
document = nextDocument;
}
}
if (document.isFile()) {
return document;
}
return null;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
static String getExtSdCardFolder(final File file) {
String[] extSdPaths = getExtSdCardPaths();
try {
for (String extSdPath : extSdPaths) {
if (file.getCanonicalPath().startsWith(extSdPath)) {
return extSdPath;
}
}
} catch (IOException e) {
return null;
}
return null;
}
static boolean requiresPermission(List<String> paths) {
boolean requiresPermission = false;
for (String path : paths) {
File file = new File(path);
requiresPermission = getExtSdCardFolder(file) != null;
if (requiresPermission) {
break;
}
}
return requiresPermission;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
static String[] getExtSdCardPaths() {
List<String> paths = new ArrayList<>();
try {
File[] externalFilesDirs = ShuttleApplication.getInstance().getExternalFilesDirs("external");
if (externalFilesDirs != null && externalFilesDirs.length > 0) {
for (File file : externalFilesDirs) {
if (file != null && !file.equals(ShuttleApplication.getInstance().getExternalFilesDir("external"))) {
int index = file.getAbsolutePath().lastIndexOf("/Android/data");
if (index < 0) {
Log.w(TAG, "Unexpected external file dir: " + file.getAbsolutePath());
} else {
String path = file.getAbsolutePath().substring(0, index);
try {
path = new File(path).getCanonicalPath();
} catch (IOException e) {
// Keep non-canonical path.
}
paths.add(path);
}
}
}
}
} catch (NoSuchMethodError e) {
Crashlytics.log("getExtSdCardPaths() failed. " + e.getMessage());
}
return paths.toArray(new String[paths.size()]);
}
static void copyFile(File sourceFile, File destFile) throws IOException {
if (!destFile.getParentFile().exists())
destFile.getParentFile().mkdirs();
if (!destFile.exists()) {
destFile.createNewFile();
}
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
static void copyFile(File sourceFile, FileOutputStream outputStream) throws IOException {
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = outputStream.getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
if (source != null) {
source.close();
}
if (destination != null) {
destination.close();
}
}
}
static void showChooseDocumentDialog(Context context, MaterialDialog.SingleButtonCallback listener, boolean hasChecked) {
MaterialDialog.Builder builder = DialogUtils.getBuilder(context)
.title(R.string.edit_tags)
.content(hasChecked ? R.string.tag_editor_document_tree_permission_failed : R.string.tag_editor_document_tree_message)
.positiveText(R.string.button_ok)
.onPositive(listener);
if (hasChecked) {
builder.negativeText(R.string.cancel);
}
builder.show();
}
}