mirror of
https://github.com/gsantner/dandelion
synced 2025-12-15 08:41:10 +01:00
Rework screenshot saving and sharing; add new share options:
* Share option: Launcher shortcut (fixes #170) * Share option: Copy link of current page to clipboard * Share otpion: Export as PDF / print
This commit is contained in:
parent
d53128e5cb
commit
51093e0c3d
35 changed files with 1222 additions and 138 deletions
34
app/src/main/java/net/gsantner/opoc/util/Callback.java
Normal file
34
app/src/main/java/net/gsantner/opoc/util/Callback.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*#######################################################
|
||||
*
|
||||
* Maintained by Gregor Santner, 2018-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class Callback {
|
||||
public interface a1<A> {
|
||||
void callback(A arg1);
|
||||
}
|
||||
|
||||
public interface a2<A, B> {
|
||||
void callback(A arg1, B arg2);
|
||||
}
|
||||
|
||||
public interface a3<A, B, C> {
|
||||
void callback(A arg1, B arg2, C arg3);
|
||||
}
|
||||
|
||||
public interface a4<A, B, C, D> {
|
||||
void callback(A arg1, B arg2, C arg3, D arg4);
|
||||
}
|
||||
|
||||
public interface a5<A, B, C, D, E> {
|
||||
void callback(A arg1, B arg2, C arg3, D arg4, E arg5);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ import android.graphics.drawable.AdaptiveIconDrawable;
|
|||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.VectorDrawable;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
|
|
@ -446,6 +447,25 @@ public class ContextUtils {
|
|||
return dp * _context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the givens paths to be scanned by MediaScanner
|
||||
*
|
||||
* @param files Files and folders to scan
|
||||
*/
|
||||
public void mediaScannerScanFile(File... files) {
|
||||
if (android.os.Build.VERSION.SDK_INT > 19) {
|
||||
String[] paths = new String[files.length];
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
paths[i] = files[i].getAbsolutePath();
|
||||
}
|
||||
MediaScannerConnection.scanFile(_context, paths, null, null);
|
||||
} else {
|
||||
for (File file : files) {
|
||||
_context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an image into a {@link ImageView} and apply a color filter
|
||||
*/
|
||||
|
|
@ -459,7 +479,10 @@ public class ContextUtils {
|
|||
*/
|
||||
public Bitmap drawableToBitmap(Drawable drawable) {
|
||||
Bitmap bitmap = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (drawable instanceof VectorDrawable || drawable instanceof VectorDrawableCompat || drawable instanceof AdaptiveIconDrawable)) {
|
||||
if (drawable instanceof VectorDrawableCompat
|
||||
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable)
|
||||
|| ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && drawable instanceof AdaptiveIconDrawable))) {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
drawable = (DrawableCompat.wrap(drawable)).mutate();
|
||||
}
|
||||
|
|
|
|||
340
app/src/main/java/net/gsantner/opoc/util/FileUtils.java
Normal file
340
app/src/main/java/net/gsantner/opoc/util/FileUtils.java
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/*#######################################################
|
||||
*
|
||||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "deprecation"})
|
||||
public class FileUtils {
|
||||
// Used on methods like copyFile(src, dst)
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
public static String readTextFile(final File file) {
|
||||
try {
|
||||
return readCloseTextStream(new FileInputStream(file));
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("readTextFile: File " + file + " not found.");
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String readCloseTextStream(final InputStream stream) {
|
||||
return readCloseTextStream(stream, true).get(0);
|
||||
}
|
||||
|
||||
public static List<String> readCloseTextStream(final InputStream stream, boolean concatToOneString) {
|
||||
final ArrayList<String> lines = new ArrayList<>();
|
||||
BufferedReader reader = null;
|
||||
String line = "";
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
reader = new BufferedReader(new InputStreamReader(stream));
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (concatToOneString) {
|
||||
sb.append(line).append('\n');
|
||||
} else {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
line = sb.toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (concatToOneString) {
|
||||
lines.clear();
|
||||
lines.add(line);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
public static byte[] readBinaryFile(final File file) {
|
||||
try {
|
||||
return readCloseBinaryStream(new FileInputStream(file), (int) file.length());
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("readBinaryFile: File " + file + " not found.");
|
||||
}
|
||||
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
public static byte[] readCloseBinaryStream(final InputStream stream, int byteCount) {
|
||||
final ArrayList<String> lines = new ArrayList<>();
|
||||
BufferedInputStream reader = null;
|
||||
byte[] buf = new byte[byteCount];
|
||||
int totalBytesRead = 0;
|
||||
try {
|
||||
reader = new BufferedInputStream(stream);
|
||||
while (totalBytesRead < byteCount) {
|
||||
int bytesRead = reader.read(buf, totalBytesRead, byteCount - totalBytesRead);
|
||||
if (bytesRead > 0) {
|
||||
totalBytesRead = totalBytesRead + bytesRead;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Read binary stream (of unknown conf size)
|
||||
public static byte[] readCloseBinaryStream(final InputStream stream) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int read;
|
||||
while ((read = stream.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, read);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
public static boolean writeFile(final File file, byte[] data) {
|
||||
try {
|
||||
OutputStream output = null;
|
||||
try {
|
||||
output = new BufferedOutputStream(new FileOutputStream(file));
|
||||
output.write(data);
|
||||
output.flush();
|
||||
return true;
|
||||
} finally {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean writeFile(final File file, final String content) {
|
||||
BufferedWriter writer = null;
|
||||
try {
|
||||
if (!file.getParentFile().isDirectory() && !file.getParentFile().mkdirs())
|
||||
return false;
|
||||
|
||||
writer = new BufferedWriter(new FileWriter(file));
|
||||
writer.write(content);
|
||||
writer.flush();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
if (writer != null) {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean copyFile(final File src, final File dst) {
|
||||
// Just touch file if src is empty
|
||||
if (src.length() == 0) {
|
||||
return touch(dst);
|
||||
}
|
||||
|
||||
InputStream is = null;
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
try {
|
||||
is = new FileInputStream(src);
|
||||
os = new FileOutputStream(dst);
|
||||
byte[] buf = new byte[BUFFER_SIZE];
|
||||
int len;
|
||||
while ((len = is.read(buf)) > 0) {
|
||||
os.write(buf, 0, len);
|
||||
}
|
||||
return true;
|
||||
} finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
if (os != null) {
|
||||
os.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns -1 if the file did not contain any of the needles, otherwise,
|
||||
// the index of which needle was found in the contents of the file.
|
||||
//
|
||||
// Needless MUST be in lower-case.
|
||||
public static int fileContains(File file, String... needles) {
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
|
||||
int i;
|
||||
String line;
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
while ((line = reader.readLine()) != null) {
|
||||
for (i = 0; i != needles.length; ++i)
|
||||
if (line.toLowerCase(Locale.ROOT).contains(needles[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static boolean deleteRecursive(final File file) {
|
||||
boolean ok = true;
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
for (File child : file.listFiles())
|
||||
ok &= deleteRecursive(child);
|
||||
}
|
||||
ok &= file.delete();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Example: Check if this is maybe a conf: (str, "jpg", "png", "jpeg")
|
||||
public static boolean hasExtension(String str, String... extensions) {
|
||||
String lc = str.toLowerCase(Locale.ROOT);
|
||||
for (String extension : extensions) {
|
||||
if (lc.endsWith("." + extension.toLowerCase(Locale.ROOT))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean renameFile(File srcFile, File destFile) {
|
||||
if (srcFile.getAbsolutePath().equals(destFile.getAbsolutePath())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// renameTo will fail in case of case-changed filename in same dir.Even on case-sensitive FS!!!
|
||||
if (srcFile.getParent().equals(destFile.getParent()) && srcFile.getName().toLowerCase(Locale.getDefault()).equals(destFile.getName().toLowerCase(Locale.getDefault()))) {
|
||||
File tmpFile = new File(destFile.getParent(), UUID.randomUUID().getLeastSignificantBits() + ".tmp");
|
||||
if (!tmpFile.exists()) {
|
||||
renameFile(srcFile, tmpFile);
|
||||
srcFile = tmpFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (!srcFile.renameTo(destFile)) {
|
||||
if (copyFile(srcFile, destFile) && !srcFile.delete()) {
|
||||
if (!destFile.delete()) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public static boolean renameFileInSameFolder(File srcFile, String destFilename) {
|
||||
return renameFile(srcFile, new File(srcFile.getParent(), destFilename));
|
||||
}
|
||||
|
||||
public static boolean touch(File file) {
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
new FileOutputStream(file).close();
|
||||
}
|
||||
return file.setLastModified(System.currentTimeMillis());
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get relative path to specified destination
|
||||
public static String relativePath(File src, File dest) {
|
||||
try {
|
||||
String[] srcSplit = (src.isDirectory() ? src : src.getParentFile()).getCanonicalPath().split(Pattern.quote(File.separator));
|
||||
String[] destSplit = dest.getCanonicalPath().split(Pattern.quote(File.separator));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i = 0;
|
||||
|
||||
for (; i < destSplit.length && i < srcSplit.length; ++i) {
|
||||
if (!destSplit[i].equals(srcSplit[i]))
|
||||
break;
|
||||
}
|
||||
if (i != srcSplit.length) {
|
||||
for (int iUpperDir = i; iUpperDir < srcSplit.length; ++iUpperDir) {
|
||||
sb.append("..");
|
||||
sb.append(File.separator);
|
||||
}
|
||||
}
|
||||
for (; i < destSplit.length; ++i) {
|
||||
sb.append(destSplit[i]);
|
||||
sb.append(File.separator);
|
||||
}
|
||||
if (!dest.getPath().endsWith("/") && !dest.getPath().endsWith("\\")) {
|
||||
sb.delete(sb.length() - File.separator.length(), sb.length());
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (IOException | NullPointerException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
208
app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java
Normal file
208
app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*#######################################################
|
||||
*
|
||||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "deprecation"})
|
||||
public class NetworkUtils {
|
||||
private static final String UTF8 = "UTF-8";
|
||||
public static final String GET = "GET";
|
||||
public static final String POST = "POST";
|
||||
public static final String PATCH = "PATCH";
|
||||
|
||||
private final static int BUFFER_SIZE = 4096;
|
||||
|
||||
// Downloads a file from the give url to the output file
|
||||
// Creates the file's parent directory if it doesn't exist
|
||||
public static boolean downloadFile(final String url, final File out) {
|
||||
return downloadFile(url, out, null);
|
||||
}
|
||||
|
||||
public static boolean downloadFile(final String url, final File out, final Callback.a1<Float> progressCallback) {
|
||||
try {
|
||||
return downloadFile(new URL(url), out, progressCallback);
|
||||
} catch (MalformedURLException e) {
|
||||
// Won't happen
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean downloadFile(final URL url, final File outFile, final Callback.a1<Float> progressCallback) {
|
||||
InputStream input = null;
|
||||
OutputStream output = null;
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.connect();
|
||||
input = connection.getInputStream();
|
||||
|
||||
if (!outFile.getParentFile().isDirectory())
|
||||
if (!outFile.getParentFile().mkdirs())
|
||||
return false;
|
||||
output = new FileOutputStream(outFile);
|
||||
|
||||
int count;
|
||||
int written = 0;
|
||||
final float invLength = 1f / connection.getContentLength();
|
||||
|
||||
byte data[] = new byte[BUFFER_SIZE];
|
||||
while ((count = input.read(data)) != -1) {
|
||||
output.write(data, 0, count);
|
||||
if (invLength != -1f && progressCallback != null) {
|
||||
written += count;
|
||||
progressCallback.callback(written * invLength);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
if (output != null)
|
||||
output.close();
|
||||
if (input != null)
|
||||
input.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
if (connection != null)
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// No parameters, method can be GET, POST, etc.
|
||||
public static String performCall(final String url, final String method) {
|
||||
try {
|
||||
return performCall(new URL(url), method, "");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String performCall(final String url, final String method, final String data) {
|
||||
try {
|
||||
return performCall(new URL(url), method, data);
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// URL encoded parameters
|
||||
public static String performCall(final String url, final String method, final HashMap<String, String> params) {
|
||||
try {
|
||||
return performCall(new URL(url), method, encodeQuery(params));
|
||||
} catch (UnsupportedEncodingException | MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Defaults to POST
|
||||
public static String performCall(final String url, final JSONObject json) {
|
||||
return performCall(url, POST, json);
|
||||
}
|
||||
|
||||
public static String performCall(final String url, final String method, final JSONObject json) {
|
||||
try {
|
||||
return performCall(new URL(url), method, json.toString());
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String performCall(final URL url, final String method, final String data) {
|
||||
try {
|
||||
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod(method);
|
||||
conn.setDoInput(true);
|
||||
|
||||
if (data != null && !data.isEmpty()) {
|
||||
conn.setDoOutput(true);
|
||||
final OutputStream output = conn.getOutputStream();
|
||||
output.write(data.getBytes(Charset.forName(UTF8)));
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
|
||||
return FileUtils.readCloseTextStream(conn.getInputStream());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String encodeQuery(final HashMap<String, String> params) throws UnsupportedEncodingException {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
if (first) first = false;
|
||||
else result.append("&");
|
||||
|
||||
result.append(URLEncoder.encode(entry.getKey(), UTF8));
|
||||
result.append("=");
|
||||
result.append(URLEncoder.encode(entry.getValue(), UTF8));
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static HashMap<String, String> getDataMap(final String query) {
|
||||
final HashMap<String, String> result = new HashMap<>();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
String name = "";
|
||||
|
||||
try {
|
||||
for (int i = 0; i < query.length(); i++) {
|
||||
char c = query.charAt(i);
|
||||
switch (c) {
|
||||
case '=':
|
||||
name = URLDecoder.decode(sb.toString(), UTF8);
|
||||
sb.setLength(0);
|
||||
break;
|
||||
case '&':
|
||||
result.put(name, URLDecoder.decode(sb.toString(), UTF8));
|
||||
sb.setLength(0);
|
||||
break;
|
||||
default:
|
||||
sb.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!name.isEmpty())
|
||||
result.put(name, URLDecoder.decode(sb.toString(), UTF8));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*#######################################################
|
||||
*
|
||||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
public class PermissionChecker {
|
||||
private static final int CODE_PERMISSION_EXTERNAL_STORAGE = 4000;
|
||||
|
||||
private Activity _activity;
|
||||
|
||||
public PermissionChecker(Activity activity) {
|
||||
_activity = activity;
|
||||
}
|
||||
|
||||
public boolean doIfExtStoragePermissionGranted(String... optionalToastMessageForKnowingWhyNeeded) {
|
||||
if (ContextCompat.checkSelfPermission(_activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
if (optionalToastMessageForKnowingWhyNeeded != null && optionalToastMessageForKnowingWhyNeeded.length > 0 && optionalToastMessageForKnowingWhyNeeded[0] != null) {
|
||||
new AlertDialog.Builder(_activity)
|
||||
.setMessage(optionalToastMessageForKnowingWhyNeeded[0])
|
||||
.setCancelable(false)
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
||||
if (android.os.Build.VERSION.SDK_INT >= 23) {
|
||||
ActivityCompat.requestPermissions(_activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE_PERMISSION_EXTERNAL_STORAGE);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
return false;
|
||||
}
|
||||
ActivityCompat.requestPermissions(_activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE_PERMISSION_EXTERNAL_STORAGE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (grantResults.length > 0) {
|
||||
switch (requestCode) {
|
||||
case CODE_PERMISSION_EXTERNAL_STORAGE: {
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mkdirIfStoragePermissionGranted(File dir) {
|
||||
return doIfExtStoragePermissionGranted() && (dir.exists() || dir.mkdirs());
|
||||
}
|
||||
}
|
||||
453
app/src/main/java/net/gsantner/opoc/util/ShareUtil.java
Normal file
453
app/src/main/java/net/gsantner/opoc/util/ShareUtil.java
Normal file
|
|
@ -0,0 +1,453 @@
|
|||
/*#######################################################
|
||||
*
|
||||
* Maintained by Gregor Santner, 2017-
|
||||
* https://gsantner.net/
|
||||
*
|
||||
* License: Apache 2.0
|
||||
* https://github.com/gsantner/opoc/#licensing
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.print.PrintAttributes;
|
||||
import android.print.PrintDocumentAdapter;
|
||||
import android.print.PrintJob;
|
||||
import android.print.PrintManager;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.content.pm.ShortcutInfoCompat;
|
||||
import android.support.v4.content.pm.ShortcutManagerCompat;
|
||||
import android.support.v4.graphics.drawable.IconCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* A utility class to ease information sharing on Android
|
||||
* Also allows to parse/fetch information out of shared information
|
||||
*/
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess", "SameParameterValue", "unused", "deprecation", "ConstantConditions", "ObsoleteSdkInt", "SpellCheckingInspection"})
|
||||
public class ShareUtil {
|
||||
public final static String EXTRA_FILEPATH = "real_file_path_2";
|
||||
public final static SimpleDateFormat SDF_RFC3339_ISH = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm", Locale.getDefault());
|
||||
public final static SimpleDateFormat SDF_SHORT = new SimpleDateFormat("yyMMdd-HHmm", Locale.getDefault());
|
||||
|
||||
|
||||
protected Context _context;
|
||||
protected String _fileProviderAuthority;
|
||||
protected String _chooserTitle;
|
||||
|
||||
public ShareUtil(Context context) {
|
||||
_context = context;
|
||||
_chooserTitle = "➥";
|
||||
}
|
||||
|
||||
public String getFileProviderAuthority() {
|
||||
if (TextUtils.isEmpty(_fileProviderAuthority)) {
|
||||
throw new RuntimeException("Error at ShareUtil.getFileProviderAuthority(): No FileProvider authority provided");
|
||||
}
|
||||
return _fileProviderAuthority;
|
||||
}
|
||||
|
||||
public ShareUtil setFileProviderAuthority(String fileProviderAuthority) {
|
||||
_fileProviderAuthority = fileProviderAuthority;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ShareUtil setChooserTitle(String title) {
|
||||
_chooserTitle = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a {@link File} to an {@link Uri}
|
||||
*
|
||||
* @param file the file
|
||||
* @return Uri for this file
|
||||
*/
|
||||
public Uri getUriByFileProviderAuthority(File file) {
|
||||
return FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to choose a handling app for given intent
|
||||
*
|
||||
* @param intent Thing to be shared
|
||||
* @param chooserText The title text for the chooser, or null for default
|
||||
*/
|
||||
public void showChooser(Intent intent, String chooserText) {
|
||||
_context.startActivity(Intent.createChooser(intent,
|
||||
chooserText != null ? chooserText : _chooserTitle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create a new desktop shortcut on the launcher. Add permissions:
|
||||
* <uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
|
||||
* <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
*
|
||||
* @param intent The intent to be invoked on tap
|
||||
* @param iconRes Icon resource for the item
|
||||
* @param title Title of the item
|
||||
*/
|
||||
public void createLauncherDesktopShortcut(Intent intent, @DrawableRes int iconRes, String title) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
if (intent.getAction() == null) {
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
}
|
||||
|
||||
ShortcutInfoCompat shortcut = new ShortcutInfoCompat.Builder(_context, Long.toString(new Random().nextLong()))
|
||||
.setIntent(intent)
|
||||
.setIcon(IconCompat.createWithResource(_context, iconRes))
|
||||
.setShortLabel(title)
|
||||
.setLongLabel(title)
|
||||
.build();
|
||||
ShortcutManagerCompat.requestPinShortcut(_context, shortcut, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create a new desktop shortcut on the launcher. This will not work on Api > 25. Add permissions:
|
||||
* <uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
|
||||
* <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
*
|
||||
* @param intent The intent to be invoked on tap
|
||||
* @param iconRes Icon resource for the item
|
||||
* @param title Title of the item
|
||||
*/
|
||||
public void createLauncherDesktopShortcutLegacy(Intent intent, @DrawableRes int iconRes, String title) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
if (intent.getAction() == null) {
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
}
|
||||
|
||||
Intent creationIntent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
|
||||
creationIntent.putExtra("duplicate", true);
|
||||
creationIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
|
||||
creationIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
|
||||
creationIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(_context, iconRes));
|
||||
_context.sendBroadcast(creationIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Share text with given mime-type
|
||||
*
|
||||
* @param text The text to share
|
||||
* @param mimeType MimeType or null (uses text/plain)
|
||||
*/
|
||||
public void shareText(String text, @Nullable String mimeType) {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, text);
|
||||
intent.setType(mimeType != null ? mimeType : "text/plain");
|
||||
showChooser(intent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Share the given file as stream with given mime-type
|
||||
*
|
||||
* @param file The file to share
|
||||
* @param mimeType The files mime type
|
||||
*/
|
||||
public void shareStream(File file, String mimeType) {
|
||||
Uri fileUri = FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
|
||||
intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath());
|
||||
intent.setType(mimeType);
|
||||
showChooser(intent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Share the given bitmap with given format
|
||||
*
|
||||
* @param bitmap Image
|
||||
* @param format A {@link Bitmap.CompressFormat}, supporting JPEG,PNG,WEBP
|
||||
* @return if success, true
|
||||
*/
|
||||
public boolean shareImage(Bitmap bitmap, Bitmap.CompressFormat format) {
|
||||
return shareImage(bitmap, format, 95, "SharedImage");
|
||||
}
|
||||
|
||||
/**
|
||||
* Share the given bitmap with given format
|
||||
*
|
||||
* @param bitmap Image
|
||||
* @param format A {@link Bitmap.CompressFormat}, supporting JPEG,PNG,WEBP
|
||||
* @param imageName Filename without extension
|
||||
* @param quality Quality of the exported image [0-100]
|
||||
* @return if success, true
|
||||
*/
|
||||
public boolean shareImage(Bitmap bitmap, Bitmap.CompressFormat format, int quality, String imageName) {
|
||||
try {
|
||||
String ext = format.name().toLowerCase();
|
||||
File file = File.createTempFile(imageName, "." + ext.replace("jpeg", "jpg"), _context.getExternalCacheDir());
|
||||
if (bitmap != null && new ContextUtils(_context).writeImageToFile(file, bitmap, format, quality)) {
|
||||
shareStream(file, "image/" + ext);
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a {@link WebView}'s contents, also allows to create a PDF
|
||||
*
|
||||
* @param webview WebView
|
||||
* @param jobName Name of the job (affects PDF name too)
|
||||
* @return {{@link PrintJob}} or null
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
@SuppressWarnings("deprecation")
|
||||
public PrintJob print(WebView webview, String jobName) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
PrintDocumentAdapter printAdapter;
|
||||
PrintManager printManager = (PrintManager) webview.getContext().getSystemService(Context.PRINT_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
printAdapter = webview.createPrintDocumentAdapter(jobName);
|
||||
} else {
|
||||
printAdapter = webview.createPrintDocumentAdapter();
|
||||
}
|
||||
if (printManager != null) {
|
||||
return printManager.print(jobName, printAdapter, new PrintAttributes.Builder().build());
|
||||
}
|
||||
} else {
|
||||
Log.e(getClass().getName(), "ERROR: Method called on too low Android API version");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See {@link #print(WebView, String) print method}
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
@SuppressWarnings("deprecation")
|
||||
public PrintJob createPdf(WebView webview, String jobName) {
|
||||
return print(webview, jobName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a picture out of {@link WebView}'s whole content
|
||||
*
|
||||
* @param webView The WebView to get contents from
|
||||
* @return A {@link Bitmap} or null
|
||||
*/
|
||||
@Nullable
|
||||
public static Bitmap getBitmapFromWebView(WebView webView) {
|
||||
try {
|
||||
//Measure WebView's content
|
||||
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
||||
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
webView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight());
|
||||
|
||||
//Build drawing cache and store its size
|
||||
webView.buildDrawingCache();
|
||||
int measuredWidth = webView.getMeasuredWidth();
|
||||
int measuredHeight = webView.getMeasuredHeight();
|
||||
|
||||
//Creates the bitmap and draw WebView's content on in
|
||||
Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.drawBitmap(bitmap, 0, bitmap.getHeight(), new Paint());
|
||||
|
||||
webView.draw(canvas);
|
||||
webView.destroyDrawingCache();
|
||||
|
||||
return bitmap;
|
||||
} catch (Exception | OutOfMemoryError e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* Replace (primary) clipboard contents with given {@code text}
|
||||
* @param text Text to be set
|
||||
*/
|
||||
public boolean setClipboard(CharSequence text) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
android.text.ClipboardManager cm = ((android.text.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE));
|
||||
if (cm != null) {
|
||||
cm.setText(text);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
android.content.ClipboardManager cm = ((android.content.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE));
|
||||
if (cm != null) {
|
||||
ClipData clip = ClipData.newPlainText(_context.getPackageName(), text);
|
||||
cm.setPrimaryClip(clip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get clipboard contents, very failsafe and compat to older android versions
|
||||
*/
|
||||
public List<String> getClipboard() {
|
||||
List<String> clipper = new ArrayList<>();
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
android.text.ClipboardManager cm = ((android.text.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE));
|
||||
if (cm != null && !TextUtils.isEmpty(cm.getText())) {
|
||||
clipper.add(cm.getText().toString());
|
||||
}
|
||||
} else {
|
||||
android.content.ClipboardManager cm = ((android.content.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE));
|
||||
if (cm != null && cm.hasPrimaryClip()) {
|
||||
ClipData data = cm.getPrimaryClip();
|
||||
for (int i = 0; data != null && i < data.getItemCount() && i < data.getItemCount(); i++) {
|
||||
ClipData.Item item = data.getItemAt(i);
|
||||
if (item != null && !TextUtils.isEmpty(item.getText())) {
|
||||
clipper.add(data.getItemAt(i).getText().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return clipper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Share given text on a hastebin compatible server
|
||||
* (https://github.com/seejohnrun/haste-server)
|
||||
* Permission needed: Internet
|
||||
* Pastes will be deleted after 30 days without access
|
||||
*
|
||||
* @param text The text to paste
|
||||
* @param callback Callback after paste try
|
||||
* @param serverOrNothing Supply one or no hastebin server. If empty, the default gets taken
|
||||
*/
|
||||
public void pasteOnHastebin(final String text, final Callback.a2<Boolean, String> callback, String... serverOrNothing) {
|
||||
final Handler handler = new Handler();
|
||||
final String server = (serverOrNothing != null && serverOrNothing.length > 0 && serverOrNothing[0] != null)
|
||||
? serverOrNothing[0] : "https://hastebin.com";
|
||||
new Thread() {
|
||||
public void run() {
|
||||
// Returns a simple result, handleable without json parser {"key":"feediyujiq"}
|
||||
String ret = NetworkUtils.performCall(server + "/documents", NetworkUtils.POST, text);
|
||||
final String key = (ret.length() > 15) ? ret.split("\"")[3] : "";
|
||||
handler.post(() -> callback.callback(!key.isEmpty(), server + "/" + key));
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draft an email with given data. Unknown data can be supplied as null.
|
||||
* This will open a chooser with installed mail clients where the mail can be sent from
|
||||
*
|
||||
* @param subject Subject (top/title) text to be prefilled in the mail
|
||||
* @param body Body (content) text to be prefilled in the mail
|
||||
* @param to recipients to be prefilled in the mail
|
||||
*/
|
||||
public void draftEmail(String subject, String body, String... to) {
|
||||
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
||||
intent.setData(Uri.parse("mailto:"));
|
||||
if (subject != null) {
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
}
|
||||
if (body != null) {
|
||||
intent.putExtra(Intent.EXTRA_TEXT, body);
|
||||
}
|
||||
if (to != null && to.length > 0 && to[0] != null) {
|
||||
intent.putExtra(Intent.EXTRA_EMAIL, to);
|
||||
}
|
||||
showChooser(intent, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to force extract a absolute filepath from an intent
|
||||
*
|
||||
* @param receivingIntent The intent from {@link Activity#getIntent()}
|
||||
* @return A file or null if extraction did not succeed
|
||||
*/
|
||||
public File extractFileFromIntent(Intent receivingIntent) {
|
||||
String action = receivingIntent.getAction();
|
||||
String type = receivingIntent.getType();
|
||||
File tmpf;
|
||||
String tmps;
|
||||
String fileStr;
|
||||
|
||||
if ((Intent.ACTION_VIEW.equals(action) || Intent.ACTION_EDIT.equals(action))) {
|
||||
// Markor, S.M.T FileManager
|
||||
if (receivingIntent.hasExtra((tmps = EXTRA_FILEPATH))) {
|
||||
return new File(receivingIntent.getStringExtra(tmps));
|
||||
}
|
||||
|
||||
// Analyze data/Uri
|
||||
Uri fileUri = receivingIntent.getData();
|
||||
if (fileUri != null && (fileStr = fileUri.toString()) != null) {
|
||||
// Uri contains file
|
||||
if (fileStr.startsWith("file://")) {
|
||||
return new File(fileUri.getPath());
|
||||
}
|
||||
if (fileStr.startsWith((tmps = "content://"))) {
|
||||
fileStr = fileStr.substring(tmps.length());
|
||||
String fileProvider = fileStr.substring(0, fileStr.indexOf("/"));
|
||||
fileStr = fileStr.substring(fileProvider.length() + 1);
|
||||
|
||||
// Some file managers dont add leading slash
|
||||
if (fileStr.startsWith("storage/")) {
|
||||
fileStr = "/" + fileStr;
|
||||
}
|
||||
// Some do add some custom prefix
|
||||
for (String prefix : new String[]{"file", "document", "root_files"}) {
|
||||
if (fileStr.startsWith(prefix)) {
|
||||
fileStr = fileStr.substring(prefix.length());
|
||||
}
|
||||
}
|
||||
// Next/OwnCloud Fileprovider
|
||||
for (String fp : new String[]{"org.nextcloud.files", "org.nextcloud.beta.files", "org.owncloud.files"}) {
|
||||
if (fileProvider.equals(fp) && fileStr.startsWith(tmps = "external_files/")) {
|
||||
return new File(Uri.decode("/storage/" + fileStr.substring(tmps.length())));
|
||||
}
|
||||
}
|
||||
// AOSP File Manager/Documents
|
||||
if (fileProvider.equals("com.android.externalstorage.documents") && fileStr.startsWith(tmps = "/primary%3A")) {
|
||||
return new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileStr.substring(tmps.length())));
|
||||
}
|
||||
// Mi File Explorer
|
||||
if (fileProvider.equals("com.mi.android.globalFileexplorer.myprovider") && fileStr.startsWith(tmps = "external_files")) {
|
||||
return new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + fileStr.substring(tmps.length())));
|
||||
}
|
||||
// URI Encoded paths with full path after content://package/
|
||||
if (fileStr.startsWith("/") || fileStr.startsWith("%2F")) {
|
||||
tmpf = new File(Uri.decode(fileStr));
|
||||
if (tmpf.exists()) {
|
||||
return tmpf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue