diff --git a/.gitignore b/.gitignore index afbdab33e..8c8ca10a2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /.idea/libraries .DS_Store /build +*.iml diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..2e7c00741 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "unifile"] + path = unifile + url = https://github.com/seven332/UniFile diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 5f8fa95eb..5ae77d6a2 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -11,6 +11,7 @@ diff --git a/.idea/modules.xml b/.idea/modules.xml index 464db56d3..63c9739be 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -4,7 +4,8 @@ + + - - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index aee72b41e..4bc09458a 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -3,6 +3,6 @@ + - - + \ No newline at end of file diff --git a/EhViewer.iml b/EhViewer.iml deleted file mode 100644 index 91efc5aa3..000000000 --- a/EhViewer.iml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore index aceae4974..df5a55a6e 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,2 +1,5 @@ /build manifest-merger-release-report.txt + +# Intellij +*.iml diff --git a/app/app.iml b/app/app.iml deleted file mode 100644 index f926f9d11..000000000 --- a/app/app.iml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 31854f9bf..3e058a93f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,4 +33,5 @@ dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' compile fileTree(dir: 'libs', include: ['*.jar']) + compile project(':unifile') } diff --git a/app/src/main/java/com/hippo/unifile/DocumentFile.java b/app/src/main/java/com/hippo/unifile/DocumentFile.java deleted file mode 100644 index b0f273d82..000000000 --- a/app/src/main/java/com/hippo/unifile/DocumentFile.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.unifile; - -import android.content.Context; -import android.net.Uri; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -class DocumentFile extends UniFile { - - private Context mContext; - private Uri mUri; - - DocumentFile(UniFile parent, Context context, Uri uri) { - super(parent); - mContext = context; - mUri = uri; - } - - @Override - public UniFile createFile(String displayName) { - UniFile child = contains(displayName); - - if (child != null) { - if (child.isFile()) { - return child; - } else { - return null; - } - } else { - final Uri result = DocumentsContractApi21.createFile(mContext, mUri, "application/octet-stream", displayName); - return (result != null) ? new DocumentFile(this, mContext, result) : null; - } - } - - @Override - public UniFile createDirectory(String displayName) { - UniFile child = contains(displayName); - - if (child != null) { - if (child.isDirectory()) { - return child; - } else { - return null; - } - } else { - final Uri result = DocumentsContractApi21.createDirectory(mContext, mUri, displayName); - return (result != null) ? new DocumentFile(this, mContext, result) : null; - } - } - - @Override - public Uri getUri() { - return mUri; - } - - @Override - public String getName() { - return DocumentsContractApi19.getName(mContext, mUri); - } - - @Override - public String getType() { - return DocumentsContractApi19.getType(mContext, mUri); - } - - @Override - public boolean isDirectory() { - return DocumentsContractApi19.isDirectory(mContext, mUri); - } - - @Override - public boolean isFile() { - return DocumentsContractApi19.isFile(mContext, mUri); - } - - @Override - public long lastModified() { - return DocumentsContractApi19.lastModified(mContext, mUri); - } - - @Override - public long length() { - return DocumentsContractApi19.length(mContext, mUri); - } - - @Override - public boolean canRead() { - return DocumentsContractApi19.canRead(mContext, mUri); - } - - @Override - public boolean canWrite() { - return DocumentsContractApi19.canWrite(mContext, mUri); - } - - @Override - public boolean delete() { - return DocumentsContractApi19.delete(mContext, mUri); - } - - @Override - public boolean exists() { - return DocumentsContractApi19.exists(mContext, mUri); - } - - @Override - public UniFile contains(String displayName) { - Uri childUri = DocumentsContractApi21.buildChildUri(mUri, displayName); - return DocumentsContractApi19.exists(mContext, childUri) ? - new DocumentFile(this, mContext, childUri) : null; - } - - @Override - public UniFile[] listFiles() { - final Uri[] result = DocumentsContractApi21.listFiles(mContext, mUri); - final UniFile[] resultFiles = new UniFile[result.length]; - for (int i = 0; i < result.length; i++) { - resultFiles[i] = new DocumentFile(this, mContext, result[i]); - } - return resultFiles; - } - - @Override - public boolean renameTo(String displayName) { - final Uri result = DocumentsContractApi21.renameTo(mContext, mUri, displayName); - if (result != null) { - mUri = result; - return true; - } else { - return false; - } - } - - @Override - public OutputStream openOutputStream() throws IOException { - return mContext.getContentResolver().openOutputStream(mUri); - } - - @Override - public OutputStream openOutputStream(boolean append) throws IOException { - return mContext.getContentResolver().openOutputStream(mUri, append ? "wa" : "w"); - } - - @Override - public InputStream openInputStream() throws IOException { - return mContext.getContentResolver().openInputStream(mUri); - } -} diff --git a/app/src/main/java/com/hippo/unifile/DocumentsContractApi19.java b/app/src/main/java/com/hippo/unifile/DocumentsContractApi19.java deleted file mode 100644 index c4c37c97e..000000000 --- a/app/src/main/java/com/hippo/unifile/DocumentsContractApi19.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.unifile; - -import android.annotation.TargetApi; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.provider.DocumentsContract; -import android.text.TextUtils; -import android.util.Log; - -@TargetApi(Build.VERSION_CODES.KITKAT) -class DocumentsContractApi19 { - private static final String TAG = "UniFile"; - - public static boolean isDocumentUri(Context context, Uri self) { - return DocumentsContract.isDocumentUri(context, self); - } - - public static String getName(Context context, Uri self) { - return queryForString(context, self, DocumentsContract.Document.COLUMN_DISPLAY_NAME, null); - } - - private static String getRawType(Context context, Uri self) { - return queryForString(context, self, DocumentsContract.Document.COLUMN_MIME_TYPE, null); - } - - public static String getType(Context context, Uri self) { - final String rawType = getRawType(context, self); - if (DocumentsContract.Document.MIME_TYPE_DIR.equals(rawType)) { - return null; - } else { - return rawType; - } - } - - public static boolean isDirectory(Context context, Uri self) { - return DocumentsContract.Document.MIME_TYPE_DIR.equals(getRawType(context, self)); - } - - public static boolean isFile(Context context, Uri self) { - final String type = getRawType(context, self); - if (DocumentsContract.Document.MIME_TYPE_DIR.equals(type) || TextUtils.isEmpty(type)) { - return false; - } else { - return true; - } - } - - public static long lastModified(Context context, Uri self) { - return queryForLong(context, self, DocumentsContract.Document.COLUMN_LAST_MODIFIED, 0); - } - - public static long length(Context context, Uri self) { - return queryForLong(context, self, DocumentsContract.Document.COLUMN_SIZE, 0); - } - - public static boolean canRead(Context context, Uri self) { - // Ignore if grant doesn't allow read - if (context.checkCallingOrSelfUriPermission(self, Intent.FLAG_GRANT_READ_URI_PERMISSION) - != PackageManager.PERMISSION_GRANTED) { - return false; - } - - // Ignore documents without MIME - if (TextUtils.isEmpty(getRawType(context, self))) { - return false; - } - - return true; - } - - public static boolean canWrite(Context context, Uri self) { - // Ignore if grant doesn't allow write - if (context.checkCallingOrSelfUriPermission(self, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) - != PackageManager.PERMISSION_GRANTED) { - return false; - } - - final String type = getRawType(context, self); - final int flags = queryForInt(context, self, DocumentsContract.Document.COLUMN_FLAGS, 0); - - // Ignore documents without MIME - if (TextUtils.isEmpty(type)) { - return false; - } - - // Deletable documents considered writable - if ((flags & DocumentsContract.Document.FLAG_SUPPORTS_DELETE) != 0) { - return true; - } - - if (DocumentsContract.Document.MIME_TYPE_DIR.equals(type) - && (flags & DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE) != 0) { - // Directories that allow create considered writable - return true; - } else if (!TextUtils.isEmpty(type) - && (flags & DocumentsContract.Document.FLAG_SUPPORTS_WRITE) != 0) { - // Writable normal files considered writable - return true; - } - - return false; - } - - public static boolean delete(Context context, Uri self) { - return DocumentsContract.deleteDocument(context.getContentResolver(), self); - } - - public static boolean exists(Context context, Uri self) { - final ContentResolver resolver = context.getContentResolver(); - - Cursor c = null; - try { - c = resolver.query(self, new String[] { - DocumentsContract.Document.COLUMN_DOCUMENT_ID }, null, null, null); - return c.getCount() > 0; - } catch (Exception e) { - Log.w(TAG, "Failed query: " + e); - return false; - } finally { - closeQuietly(c); - } - } - - private static String queryForString(Context context, Uri self, String column, - String defaultValue) { - final ContentResolver resolver = context.getContentResolver(); - - Cursor c = null; - try { - c = resolver.query(self, new String[] { column }, null, null, null); - if (c.moveToFirst() && !c.isNull(0)) { - return c.getString(0); - } else { - return defaultValue; - } - } catch (Exception e) { - Log.w(TAG, "Failed query: " + e); - return defaultValue; - } finally { - closeQuietly(c); - } - } - - private static int queryForInt(Context context, Uri self, String column, - int defaultValue) { - return (int) queryForLong(context, self, column, defaultValue); - } - - private static long queryForLong(Context context, Uri self, String column, - long defaultValue) { - final ContentResolver resolver = context.getContentResolver(); - - Cursor c = null; - try { - c = resolver.query(self, new String[] { column }, null, null, null); - if (c.moveToFirst() && !c.isNull(0)) { - return c.getLong(0); - } else { - return defaultValue; - } - } catch (Exception e) { - Log.w(TAG, "Failed query: " + e); - return defaultValue; - } finally { - closeQuietly(c); - } - } - - private static void closeQuietly(AutoCloseable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (RuntimeException rethrown) { - throw rethrown; - } catch (Exception ignored) { - } - } - } -} diff --git a/app/src/main/java/com/hippo/unifile/DocumentsContractApi21.java b/app/src/main/java/com/hippo/unifile/DocumentsContractApi21.java deleted file mode 100644 index 8042e169c..000000000 --- a/app/src/main/java/com/hippo/unifile/DocumentsContractApi21.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.unifile; - -import android.annotation.TargetApi; -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.provider.DocumentsContract; -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; - -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -class DocumentsContractApi21 { - private static final String TAG = "UniFile"; - - private static final String PATH_DOCUMENT = "document"; - private static final String PATH_TREE = "tree"; - - public static Uri createFile(Context context, Uri self, String mimeType, - String displayName) { - return DocumentsContract.createDocument(context.getContentResolver(), self, mimeType, - displayName); - } - - public static Uri createDirectory(Context context, Uri self, String displayName) { - return createFile(context, self, DocumentsContract.Document.MIME_TYPE_DIR, displayName); - } - - public static Uri prepareTreeUri(Uri treeUri) { - return DocumentsContract.buildDocumentUriUsingTree(treeUri, - DocumentsContract.getTreeDocumentId(treeUri)); - } - - public static String getTreeDocumentPath(Uri documentUri) { - final List paths = documentUri.getPathSegments(); - if (paths.size() >= 4 && PATH_TREE.equals(paths.get(0)) && PATH_DOCUMENT.equals(paths.get(2))) { - return paths.get(3); - } - throw new IllegalArgumentException("Invalid URI: " + documentUri); - } - - public static Uri buildChildUri(Uri uri, String displayName) { - return DocumentsContract.buildDocumentUriUsingTree(uri, - getTreeDocumentPath(uri) + "/" + displayName); - } - - public static Uri[] listFiles(Context context, Uri self) { - final ContentResolver resolver = context.getContentResolver(); - final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(self, - DocumentsContract.getDocumentId(self)); - final ArrayList results = new ArrayList(); - - Cursor c = null; - try { - c = resolver.query(childrenUri, new String[] { - DocumentsContract.Document.COLUMN_DOCUMENT_ID }, null, null, null); - while (c.moveToNext()) { - final String documentId = c.getString(0); - final Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(self, - documentId); - results.add(documentUri); - } - } catch (Exception e) { - Log.w(TAG, "Failed query: " + e); - } finally { - closeQuietly(c); - } - - return results.toArray(new Uri[results.size()]); - } - - public static Uri renameTo(Context context, Uri self, String displayName) { - return DocumentsContract.renameDocument(context.getContentResolver(), self, displayName); - } - - private static void closeQuietly(AutoCloseable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (RuntimeException rethrown) { - throw rethrown; - } catch (Exception ignored) { - } - } - } -} diff --git a/app/src/main/java/com/hippo/unifile/RawFile.java b/app/src/main/java/com/hippo/unifile/RawFile.java deleted file mode 100644 index ab4540d4d..000000000 --- a/app/src/main/java/com/hippo/unifile/RawFile.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.unifile; - -import android.net.Uri; -import android.util.Log; -import android.webkit.MimeTypeMap; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; - -class RawFile extends UniFile { - private File mFile; - - RawFile(UniFile parent, File file) { - super(parent); - mFile = file; - } - - @Override - public UniFile createFile(String displayName) { - final File target = new File(mFile, displayName); - try { - target.createNewFile(); - return new RawFile(this, target); - } catch (IOException e) { - Log.w(TAG, "Failed to createFile: " + e); - return null; - } - } - - @Override - public UniFile createDirectory(String displayName) { - final File target = new File(mFile, displayName); - if (target.isDirectory() || target.mkdir()) { - return new RawFile(this, target); - } else { - return null; - } - } - - @Override - public Uri getUri() { - return Uri.fromFile(mFile); - } - - @Override - public String getName() { - return mFile.getName(); - } - - @Override - public String getType() { - if (mFile.isDirectory()) { - return null; - } else { - return getTypeForName(mFile.getName()); - } - } - - @Override - public boolean isDirectory() { - return mFile.isDirectory(); - } - - @Override - public boolean isFile() { - return mFile.isFile(); - } - - @Override - public long lastModified() { - return mFile.lastModified(); - } - - @Override - public long length() { - return mFile.length(); - } - - @Override - public boolean canRead() { - return mFile.canRead(); - } - - @Override - public boolean canWrite() { - return mFile.canWrite(); - } - - @Override - public boolean delete() { - deleteContents(mFile); - return mFile.delete(); - } - - @Override - public boolean exists() { - return mFile.exists(); - } - - @Override - public UniFile contains(String displayName) { - final File child = new File(mFile, displayName); - return child.exists() ? new RawFile(this, child) : null; - } - - @Override - public UniFile[] listFiles() { - final ArrayList results = new ArrayList(); - final File[] files = mFile.listFiles(); - if (files != null) { - for (File file : files) { - results.add(new RawFile(this, file)); - } - } - return results.toArray(new UniFile[results.size()]); - } - - @Override - public boolean renameTo(String displayName) { - final File target = new File(mFile.getParentFile(), displayName); - if (mFile.renameTo(target)) { - mFile = target; - return true; - } else { - return false; - } - } - - @Override - public OutputStream openOutputStream() throws IOException { - return new FileOutputStream(mFile); - } - - @Override - public OutputStream openOutputStream(boolean append) throws IOException { - return new FileOutputStream(mFile, append); - } - - @Override - public InputStream openInputStream() throws IOException { - return new FileInputStream(mFile); - } - - private static String getTypeForName(String name) { - final int lastDot = name.lastIndexOf('.'); - if (lastDot >= 0) { - final String extension = name.substring(lastDot + 1).toLowerCase(); - final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - if (mime != null) { - return mime; - } - } - - return "application/octet-stream"; - } - - private static boolean deleteContents(File dir) { - File[] files = dir.listFiles(); - boolean success = true; - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - success &= deleteContents(file); - } - if (!file.delete()) { - Log.w(TAG, "Failed to delete " + file); - success = false; - } - } - } - return success; - } -} diff --git a/app/src/main/java/com/hippo/unifile/UniFile.java b/app/src/main/java/com/hippo/unifile/UniFile.java deleted file mode 100644 index 95e832d30..000000000 --- a/app/src/main/java/com/hippo/unifile/UniFile.java +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.unifile; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Representation of a document backed by either a - * {@link android.provider.DocumentsProvider} or a raw file on disk. This is a - * utility class designed to emulate the traditional {@link File} interface. It - * offers a simplified view of a tree of documents, but it has substantial - * overhead. For optimal performance and a richer feature set, use the - * {@link android.provider.DocumentsContract} methods and constants directly. - *

- * There are several differences between documents and traditional files: - *

    - *
  • Documents express their display name and MIME type as separate fields, - * instead of relying on file extensions. Some documents providers may still - * choose to append extensions to their display names, but that's an - * implementation detail. - *
  • A single document may appear as the child of multiple directories, so it - * doesn't inherently know who its parent is. That is, documents don't have a - * strong notion of path. You can easily traverse a tree of documents from - * parent to child, but not from child to parent. - *
  • Each document has a unique identifier within that provider. This - * identifier is an opaque implementation detail of the provider, and - * as such it must not be parsed. - *
- *

- * Before using this class, first consider if you really need access to an - * entire subtree of documents. The principle of least privilege dictates that - * you should only ask for access to documents you really need. If you only need - * the user to pick a single file, use {@link Intent#ACTION_OPEN_DOCUMENT} or - * {@link Intent#ACTION_GET_CONTENT}. If you want to let the user pick multiple - * files, add {@link Intent#EXTRA_ALLOW_MULTIPLE}. If you only need the user to - * save a single file, use {@link Intent#ACTION_CREATE_DOCUMENT}. - *

- * If you really do need full access to an entire subtree of documents, start by - * launching {@link Intent#ACTION_OPEN_DOCUMENT_TREE} to let the user pick a - * directory. Then pass the resulting {@link Intent#getData()} into - * {@link #fromTreeUri(Context, Uri)} to start working with the user selected - * tree. - *

- * As you navigate the tree of UniFile instances, you can always use - * {@link #getUri()} to obtain the Uri representing the underlying document for - * that object, for use with {@link ContentResolver#openInputStream(Uri)}, etc. - *

- * To simplify your code on devices running - * {@link Build.VERSION_CODES#KITKAT} or earlier, you can use - * {@link #fromFile(File)} which emulates the behavior of a - * {@link android.provider.DocumentsProvider}. - * - * @see android.provider.DocumentsProvider - * @see android.provider.DocumentsContract - */ -public abstract class UniFile { - static final String TAG = "UniFile"; - - private final UniFile mParent; - - UniFile(UniFile parent) { - mParent = parent; - } - - /** - * Create a {@link UniFile} representing the filesystem tree rooted at - * the given {@link Uri}. This doesn't give you any additional access to the - * underlying files beyond what your app already has. - *

- * {@link #getUri()} will return {@code file://} Uris for files explored - * through this tree. - */ - public static UniFile fromFile(File file) { - return new RawFile(null, file); - } - - /** - * Create a {@link UniFile} representing the document tree rooted at - * the given {@link Uri}. This is only useful on devices running - * {@link Build.VERSION_CODES#LOLLIPOP} or later, and will return - * {@code null} when called on earlier platform versions. - * - * @param treeUri the {@link Intent#getData()} from a successful - * {@link Intent#ACTION_OPEN_DOCUMENT_TREE} request. - */ - public static UniFile fromTreeUri(Context context, Uri treeUri) { - final int version = Build.VERSION.SDK_INT; - if (version >= 21) { - return new DocumentFile(null, context, - DocumentsContractApi21.prepareTreeUri(treeUri)); - } else { - return null; - } - } - - /** - * Test if given Uri is backed by a - * {@link android.provider.DocumentsProvider}. - */ - public static boolean isDocumentUri(Context context, Uri uri) { - final int version = Build.VERSION.SDK_INT; - if (version >= 19) { - return DocumentsContractApi19.isDocumentUri(context, uri); - } else { - return false; - } - } - - /** - * Create a new document as a direct child of this directory. - * - * @param displayName name of new document, without any file extension - * appended; the underlying provider may choose to append the - * extension - * @return file representing newly created document, or null if failed - * @see android.provider.DocumentsContract#createDocument(ContentResolver, - * Uri, String, String) - */ - public abstract UniFile createFile(String displayName); - - /** - * Create a new directory as a direct child of this directory. - * - * @param displayName name of new directory - * @return file representing newly created directory, or null if failed - * @see android.provider.DocumentsContract#createDocument(ContentResolver, - * Uri, String, String) - */ - public abstract UniFile createDirectory(String displayName); - - /** - * Return a Uri for the underlying document represented by this file. This - * can be used with other platform APIs to manipulate or share the - * underlying content. You can use {@link #isDocumentUri(Context, Uri)} to - * test if the returned Uri is backed by a - * {@link android.provider.DocumentsProvider}. - * - * @see Intent#setData(Uri) - * @see Intent#setClipData(android.content.ClipData) - * @see ContentResolver#openInputStream(Uri) - * @see ContentResolver#openOutputStream(Uri) - * @see ContentResolver#openFileDescriptor(Uri, String) - */ - public abstract Uri getUri(); - - /** - * Return the display name of this document. - * - * @see android.provider.DocumentsContract.Document#COLUMN_DISPLAY_NAME - */ - public abstract String getName(); - - /** - * Return the MIME type of this document. - * - * @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE - */ - public abstract String getType(); - - /** - * Return the parent file of this document. Only defined inside of the - * user-selected tree; you can never escape above the top of the tree. - *

- * The underlying {@link android.provider.DocumentsProvider} only defines a - * forward mapping from parent to child, so the reverse mapping of child to - * parent offered here is purely a convenience method, and it may be - * incorrect if the underlying tree structure changes. - */ - public UniFile getParentFile() { - return mParent; - } - - /** - * Indicates if this file represents a directory. - * - * @return {@code true} if this file is a directory, {@code false} - * otherwise. - * @see android.provider.DocumentsContract.Document#MIME_TYPE_DIR - */ - public abstract boolean isDirectory(); - - /** - * Indicates if this file represents a file. - * - * @return {@code true} if this file is a file, {@code false} otherwise. - * @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE - */ - public abstract boolean isFile(); - - /** - * Returns the time when this file was last modified, measured in - * milliseconds since January 1st, 1970, midnight. Returns 0 if the file - * does not exist, or if the modified time is unknown. - * - * @return the time when this file was last modified. - * @see android.provider.DocumentsContract.Document#COLUMN_LAST_MODIFIED - */ - public abstract long lastModified(); - - /** - * Returns the length of this file in bytes. Returns 0 if the file does not - * exist, or if the length is unknown. The result for a directory is not - * defined. - * - * @return the number of bytes in this file. - * @see android.provider.DocumentsContract.Document#COLUMN_SIZE - */ - public abstract long length(); - - /** - * Indicates whether the current context is allowed to read from this file. - * - * @return {@code true} if this file can be read, {@code false} otherwise. - */ - public abstract boolean canRead(); - - /** - * Indicates whether the current context is allowed to write to this file. - * - * @return {@code true} if this file can be written, {@code false} - * otherwise. - * @see android.provider.DocumentsContract.Document#COLUMN_FLAGS - * @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE - * @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE - * @see android.provider.DocumentsContract.Document#FLAG_DIR_SUPPORTS_CREATE - */ - public abstract boolean canWrite(); - - /** - * Deletes this file. - *

- * Note that this method does not throw {@code IOException} on - * failure. Callers must check the return value. - * - * @return {@code true} if this file was deleted, {@code false} otherwise. - * @see android.provider.DocumentsContract#deleteDocument(ContentResolver, - * Uri) - */ - public abstract boolean delete(); - - /** - * Returns a boolean indicating whether this file can be found. - * - * @return {@code true} if this file exists, {@code false} otherwise. - */ - public abstract boolean exists(); - - /** - * Returns the file contained in the directory represented by this - * file. - * - * @return the file, or null if it does not exist. - */ - public abstract UniFile contains(String displayName); - - /** - * Returns an array of files contained in the directory represented by this - * file. - * - * @return an array of files or {@code null}. - * @see android.provider.DocumentsContract#buildChildDocumentsUriUsingTree(Uri, - * String) - */ - public abstract UniFile[] listFiles(); - - /** - * Search through {@link #listFiles()} for the first document matching the - * given display name. Returns {@code null} when no matching document is - * found. - */ - public UniFile findFile(String displayName) { - for (UniFile doc : listFiles()) { - if (displayName.equals(doc.getName())) { - return doc; - } - } - return null; - } - - /** - * Renames this file to {@code displayName}. - *

- * Note that this method does not throw {@code IOException} on - * failure. Callers must check the return value. - *

- * Some providers may need to create a new document to reflect the rename, - * potentially with a different MIME type, so {@link #getUri()} and - * {@link #getType()} may change to reflect the rename. - *

- * When renaming a directory, children previously enumerated through - * {@link #listFiles()} may no longer be valid. - * - * @param displayName the new display name. - * @return true on success. - * @see android.provider.DocumentsContract#renameDocument(ContentResolver, - * Uri, String) - */ - public abstract boolean renameTo(String displayName); - - /** - * Open a stream on to the content associated with the file, clean it if it exists - * - * @return the {@link OutputStream} - * @throws IOException - */ - public abstract OutputStream openOutputStream() throws IOException; - - /** - * Open a stream on to the content associated with the file - * - * @param append {@code true} for do not clean it if it exists - * @return the {@link OutputStream} - * @throws IOException - */ - public abstract OutputStream openOutputStream(boolean append) throws IOException; - - /** - * Open a stream on to the content associated with the file - * - * @return the {@link InputStream} - * @throws IOException - */ - public abstract InputStream openInputStream() throws IOException; -} diff --git a/settings.gradle b/settings.gradle index e7b4def49..da52a68e0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app' +include ':app', ':unifile'