mirror of
https://github.com/gsantner/dandelion
synced 2024-11-24 13:22:08 +01:00
Update opoc
Update shared helper utilities of my projects to latest state
This commit is contained in:
parent
1948c28cff
commit
7361d4bc3f
9 changed files with 286 additions and 112 deletions
|
@ -16,6 +16,7 @@ import android.support.annotation.LayoutRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
|
@ -143,4 +144,17 @@ public abstract class GsFragmentBase extends Fragment {
|
||||||
public Menu getFragmentMenu() {
|
public Menu getFragmentMenu() {
|
||||||
return _fragmentMenu;
|
return _fragmentMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the toolbar from activity
|
||||||
|
* Requires id to be set to @+id/toolbar
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
protected Toolbar getToolbar() {
|
||||||
|
try {
|
||||||
|
return (Toolbar) getActivity().findViewById(new ContextUtils(getActivity()).getResId(ContextUtils.ResType.ID, "toolbar"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -547,7 +547,7 @@ public class SharedPreferencesPropertyBackend implements PropertyBackend<String,
|
||||||
*/
|
*/
|
||||||
public Date getDateOfDaysAgo(int days) {
|
public Date getDateOfDaysAgo(int days) {
|
||||||
Calendar cal = new GregorianCalendar();
|
Calendar cal = new GregorianCalendar();
|
||||||
cal.add(Calendar.DAY_OF_MONTH, -days);
|
cal.add(Calendar.DATE, -days);
|
||||||
return cal.getTime();
|
return cal.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,11 @@
|
||||||
package net.gsantner.opoc.ui;
|
package net.gsantner.opoc.ui;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.support.annotation.ColorInt;
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
@ -23,6 +26,7 @@ import android.support.v7.widget.AppCompatEditText;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -56,9 +60,14 @@ public class SearchOrCustomTextDialog {
|
||||||
public Callback.a1<String> callback;
|
public Callback.a1<String> callback;
|
||||||
public List<? extends CharSequence> data = new ArrayList<>();
|
public List<? extends CharSequence> data = new ArrayList<>();
|
||||||
public List<? extends CharSequence> highlightData = new ArrayList<>();
|
public List<? extends CharSequence> highlightData = new ArrayList<>();
|
||||||
|
public List<Integer> iconsForData = new ArrayList<>();
|
||||||
public String messageText = "";
|
public String messageText = "";
|
||||||
public boolean isSearchEnabled = true;
|
public boolean isSearchEnabled = true;
|
||||||
public boolean isDarkDialog = false;
|
public boolean isDarkDialog = false;
|
||||||
|
public int dialogWidthDp = WindowManager.LayoutParams.MATCH_PARENT;
|
||||||
|
public int dialogHeightDp = WindowManager.LayoutParams.WRAP_CONTENT;
|
||||||
|
public int gravity = Gravity.NO_GRAVITY;
|
||||||
|
public int searchInputType = 0;
|
||||||
|
|
||||||
@ColorInt
|
@ColorInt
|
||||||
public int textColor = 0xFF000000;
|
public int textColor = 0xFF000000;
|
||||||
|
@ -89,6 +98,17 @@ public class SearchOrCustomTextDialog {
|
||||||
TextView textView = (TextView) super.getView(pos, convertView, parent);
|
TextView textView = (TextView) super.getView(pos, convertView, parent);
|
||||||
String text = textView.getText().toString();
|
String text = textView.getText().toString();
|
||||||
|
|
||||||
|
int posInOriginalList = dopt.data.indexOf(text);
|
||||||
|
if (posInOriginalList >= 0 && dopt.iconsForData != null && posInOriginalList < dopt.iconsForData.size() && dopt.iconsForData.get(posInOriginalList) != 0) {
|
||||||
|
textView.setCompoundDrawablesWithIntrinsicBounds(dopt.iconsForData.get(posInOriginalList), 0, 0, 0);
|
||||||
|
textView.setCompoundDrawablePadding(32);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
textView.setCompoundDrawableTintList(ColorStateList.valueOf(dopt.isDarkDialog ? Color.WHITE : Color.BLACK));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
boolean hl = dopt.highlightData.contains(text);
|
boolean hl = dopt.highlightData.contains(text);
|
||||||
textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor);
|
textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor);
|
||||||
textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL);
|
textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL);
|
||||||
|
@ -132,6 +152,7 @@ public class SearchOrCustomTextDialog {
|
||||||
searchEditText.setTextColor(dopt.textColor);
|
searchEditText.setTextColor(dopt.textColor);
|
||||||
searchEditText.setHintTextColor((dopt.textColor & 0x00FFFFFF) | 0x99000000);
|
searchEditText.setHintTextColor((dopt.textColor & 0x00FFFFFF) | 0x99000000);
|
||||||
searchEditText.setHint(dopt.searchHintText);
|
searchEditText.setHint(dopt.searchHintText);
|
||||||
|
searchEditText.setInputType(dopt.searchInputType == 0 ? searchEditText.getInputType() : dopt.searchInputType);
|
||||||
|
|
||||||
searchEditText.addTextChangedListener(new TextWatcher() {
|
searchEditText.addTextChangedListener(new TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -166,9 +187,11 @@ public class SearchOrCustomTextDialog {
|
||||||
dialogBuilder.setMessage(dopt.messageText);
|
dialogBuilder.setMessage(dopt.messageText);
|
||||||
}
|
}
|
||||||
dialogBuilder.setView(linearLayout)
|
dialogBuilder.setView(linearLayout)
|
||||||
.setTitle(dopt.titleText)
|
|
||||||
.setOnCancelListener(null)
|
.setOnCancelListener(null)
|
||||||
.setNegativeButton(dopt.cancelButtonText, (dialogInterface, i) -> dialogInterface.dismiss());
|
.setNegativeButton(dopt.cancelButtonText, (dialogInterface, i) -> dialogInterface.dismiss());
|
||||||
|
if (dopt.titleText != 0) {
|
||||||
|
dialogBuilder.setTitle(dopt.titleText);
|
||||||
|
}
|
||||||
if (dopt.isSearchEnabled) {
|
if (dopt.isSearchEnabled) {
|
||||||
dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> {
|
dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> {
|
||||||
dialogInterface.dismiss();
|
dialogInterface.dismiss();
|
||||||
|
@ -204,7 +227,15 @@ public class SearchOrCustomTextDialog {
|
||||||
}
|
}
|
||||||
dialog.show();
|
dialog.show();
|
||||||
if ((w = dialog.getWindow()) != null) {
|
if ((w = dialog.getWindow()) != null) {
|
||||||
w.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
|
int ds_w = dopt.dialogWidthDp < 100 ? dopt.dialogWidthDp : ((int) (dopt.dialogWidthDp * activity.getResources().getDisplayMetrics().density));
|
||||||
|
int ds_h = dopt.dialogHeightDp < 100 ? dopt.dialogHeightDp : ((int) (dopt.dialogHeightDp * activity.getResources().getDisplayMetrics().density));
|
||||||
|
w.setLayout(ds_w, ds_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((w = dialog.getWindow()) != null && dopt.gravity != Gravity.NO_GRAVITY) {
|
||||||
|
WindowManager.LayoutParams wlp = w.getAttributes();
|
||||||
|
wlp.gravity = dopt.gravity;
|
||||||
|
w.setAttributes(wlp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dopt.isSearchEnabled) {
|
if (dopt.isSearchEnabled) {
|
||||||
|
|
|
@ -12,6 +12,11 @@ package net.gsantner.opoc.util;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class Callback {
|
public class Callback {
|
||||||
|
|
||||||
|
public interface a0 {
|
||||||
|
void callback();
|
||||||
|
}
|
||||||
|
|
||||||
public interface a1<A> {
|
public interface a1<A> {
|
||||||
void callback(A arg1);
|
void callback(A arg1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.os.VibrationEffect;
|
||||||
|
import android.os.Vibrator;
|
||||||
import android.support.annotation.ColorInt;
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.annotation.ColorRes;
|
import android.support.annotation.ColorRes;
|
||||||
import android.support.annotation.DrawableRes;
|
import android.support.annotation.DrawableRes;
|
||||||
|
@ -51,7 +53,9 @@ import android.support.graphics.drawable.VectorDrawableCompat;
|
||||||
import android.support.v4.app.ActivityManagerCompat;
|
import android.support.v4.app.ActivityManagerCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v4.graphics.drawable.DrawableCompat;
|
import android.support.v4.graphics.drawable.DrawableCompat;
|
||||||
|
import android.support.v4.text.TextUtilsCompat;
|
||||||
import android.support.v4.util.Pair;
|
import android.support.v4.util.Pair;
|
||||||
|
import android.support.v4.view.ViewCompat;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.InputFilter;
|
import android.text.InputFilter;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
|
@ -82,10 +86,11 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static android.content.Context.VIBRATOR_SERVICE;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.graphics.Bitmap.CompressFormat;
|
import static android.graphics.Bitmap.CompressFormat;
|
||||||
|
|
||||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "ObsoleteSdkInt", "deprecation", "SpellCheckingInspection"})
|
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "ObsoleteSdkInt", "deprecation", "SpellCheckingInspection", "TryFinallyCanBeTryWithResources", "UnusedAssignment"})
|
||||||
public class ContextUtils {
|
public class ContextUtils {
|
||||||
//
|
//
|
||||||
// Members, Constructors
|
// Members, Constructors
|
||||||
|
@ -117,21 +122,29 @@ public class ContextUtils {
|
||||||
*
|
*
|
||||||
* @return A valid id if the id could be found, else 0
|
* @return A valid id if the id could be found, else 0
|
||||||
*/
|
*/
|
||||||
public int getResId(ResType resType, final String name) {
|
public int getResId(final ResType resType, final String name) {
|
||||||
return _context.getResources().getIdentifier(name, resType.name().toLowerCase(), _context.getPackageName());
|
try {
|
||||||
|
return _context.getResources().getIdentifier(name, resType.name().toLowerCase(), _context.getPackageName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get String by given string ressource id (nuermic)
|
* Get String by given string ressource id (nuermic)
|
||||||
*/
|
*/
|
||||||
public String rstr(@StringRes int strResId) {
|
public String rstr(@StringRes final int strResId) {
|
||||||
return _context.getString(strResId);
|
try {
|
||||||
|
return _context.getString(strResId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get String by given string ressource identifier (textual)
|
* Get String by given string ressource identifier (textual)
|
||||||
*/
|
*/
|
||||||
public String rstr(String strResKey) {
|
public String rstr(final String strResKey) {
|
||||||
try {
|
try {
|
||||||
return rstr(getResId(ResType.STRING, strResKey));
|
return rstr(getResId(ResType.STRING, strResKey));
|
||||||
} catch (Resources.NotFoundException e) {
|
} catch (Resources.NotFoundException e) {
|
||||||
|
@ -142,14 +155,22 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Get drawable from given ressource identifier
|
* Get drawable from given ressource identifier
|
||||||
*/
|
*/
|
||||||
public Drawable rdrawable(@DrawableRes int resId) {
|
public Drawable rdrawable(@DrawableRes final int resId) {
|
||||||
return ContextCompat.getDrawable(_context, resId);
|
try {
|
||||||
|
return ContextCompat.getDrawable(_context, resId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get color by given color ressource id
|
* Get color by given color ressource id
|
||||||
*/
|
*/
|
||||||
public int rcolor(@ColorRes int resId) {
|
public int rcolor(@ColorRes final int resId) {
|
||||||
|
if (resId == 0) {
|
||||||
|
Log.e(getClass().getName(), "ContextUtils::rcolor: resId is 0!");
|
||||||
|
return Color.BLACK;
|
||||||
|
}
|
||||||
return ContextCompat.getColor(_context, resId);
|
return ContextCompat.getColor(_context, resId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,12 +196,12 @@ public class ContextUtils {
|
||||||
* @param intColor The color coded in int
|
* @param intColor The color coded in int
|
||||||
* @param withAlpha Optional; Set first bool parameter to true to also include alpha value
|
* @param withAlpha Optional; Set first bool parameter to true to also include alpha value
|
||||||
*/
|
*/
|
||||||
public String colorToHexString(int intColor, boolean... withAlpha) {
|
public static String colorToHexString(final int intColor, final boolean... withAlpha) {
|
||||||
boolean a = withAlpha != null && withAlpha.length >= 1 && withAlpha[0];
|
boolean a = withAlpha != null && withAlpha.length >= 1 && withAlpha[0];
|
||||||
return String.format(a ? "#%08X" : "#%06X", (a ? 0xFFFFFFFF : 0xFFFFFF) & intColor);
|
return String.format(a ? "#%08X" : "#%06X", (a ? 0xFFFFFFFF : 0xFFFFFF) & intColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAndroidVersion() {
|
public static String getAndroidVersion() {
|
||||||
return Build.VERSION.RELEASE + " (" + Build.VERSION.SDK_INT + ")";
|
return Build.VERSION.RELEASE + " (" + Build.VERSION.SDK_INT + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +226,7 @@ public class ContextUtils {
|
||||||
src = _context.getPackageManager().getInstallerPackageName(getPackageIdManifest());
|
src = _context.getPackageManager().getInstallerPackageName(getPackageIdManifest());
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(src)) {
|
if (src == null || src.trim().isEmpty()) {
|
||||||
return "Sideloaded";
|
return "Sideloaded";
|
||||||
} else if (src.toLowerCase().contains(".amazon.")) {
|
} else if (src.toLowerCase().contains(".amazon.")) {
|
||||||
return "Amazon Appstore";
|
return "Amazon Appstore";
|
||||||
|
@ -213,7 +234,7 @@ public class ContextUtils {
|
||||||
switch (src) {
|
switch (src) {
|
||||||
case "com.android.vending":
|
case "com.android.vending":
|
||||||
case "com.google.android.feedback": {
|
case "com.google.android.feedback": {
|
||||||
return "Google Play Store";
|
return "Google Play";
|
||||||
}
|
}
|
||||||
case "org.fdroid.fdroid.privileged":
|
case "org.fdroid.fdroid.privileged":
|
||||||
case "org.fdroid.fdroid": {
|
case "org.fdroid.fdroid": {
|
||||||
|
@ -237,12 +258,12 @@ public class ContextUtils {
|
||||||
* If the parameter is an string a browser will get triggered
|
* If the parameter is an string a browser will get triggered
|
||||||
*/
|
*/
|
||||||
public void openWebpageInExternalBrowser(final String url) {
|
public void openWebpageInExternalBrowser(final String url) {
|
||||||
Uri uri = Uri.parse(url);
|
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
|
||||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
try {
|
try {
|
||||||
|
Uri uri = Uri.parse(url);
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||||
|
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||||
_context.startActivity(intent);
|
_context.startActivity(intent);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,7 +273,7 @@ public class ContextUtils {
|
||||||
*/
|
*/
|
||||||
public String getPackageIdManifest() {
|
public String getPackageIdManifest() {
|
||||||
String pkg = rstr("manifest_package_id");
|
String pkg = rstr("manifest_package_id");
|
||||||
return pkg != null ? pkg : _context.getPackageName();
|
return !TextUtils.isEmpty(pkg) ? pkg : _context.getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -270,7 +291,7 @@ public class ContextUtils {
|
||||||
* of the package set in manifest (root element).
|
* of the package set in manifest (root element).
|
||||||
* Falls back to applicationId of the app which may differ from manifest.
|
* Falls back to applicationId of the app which may differ from manifest.
|
||||||
*/
|
*/
|
||||||
public Object getBuildConfigValue(String fieldName) {
|
public Object getBuildConfigValue(final String fieldName) {
|
||||||
String pkg = getPackageIdManifest() + ".BuildConfig";
|
String pkg = getPackageIdManifest() + ".BuildConfig";
|
||||||
try {
|
try {
|
||||||
Class<?> c = Class.forName(pkg);
|
Class<?> c = Class.forName(pkg);
|
||||||
|
@ -284,9 +305,9 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Get a BuildConfig bool value
|
* Get a BuildConfig bool value
|
||||||
*/
|
*/
|
||||||
public Boolean bcbool(String fieldName, Boolean defaultValue) {
|
public Boolean bcbool(final String fieldName, final Boolean defaultValue) {
|
||||||
Object field = getBuildConfigValue(fieldName);
|
Object field = getBuildConfigValue(fieldName);
|
||||||
if (field != null && field instanceof Boolean) {
|
if (field instanceof Boolean) {
|
||||||
return (Boolean) field;
|
return (Boolean) field;
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
@ -295,9 +316,9 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Get a BuildConfig string value
|
* Get a BuildConfig string value
|
||||||
*/
|
*/
|
||||||
public String bcstr(String fieldName, String defaultValue) {
|
public String bcstr(final String fieldName, final String defaultValue) {
|
||||||
Object field = getBuildConfigValue(fieldName);
|
Object field = getBuildConfigValue(fieldName);
|
||||||
if (field != null && field instanceof String) {
|
if (field instanceof String) {
|
||||||
return (String) field;
|
return (String) field;
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
@ -306,9 +327,9 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Get a BuildConfig string value
|
* Get a BuildConfig string value
|
||||||
*/
|
*/
|
||||||
public Integer bcint(String fieldName, int defaultValue) {
|
public Integer bcint(final String fieldName, final int defaultValue) {
|
||||||
Object field = getBuildConfigValue(fieldName);
|
Object field = getBuildConfigValue(fieldName);
|
||||||
if (field != null && field instanceof Integer) {
|
if (field instanceof Integer) {
|
||||||
return (Integer) field;
|
return (Integer) field;
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
@ -396,8 +417,8 @@ public class ContextUtils {
|
||||||
* Check if app with given {@code packageName} is installed
|
* Check if app with given {@code packageName} is installed
|
||||||
*/
|
*/
|
||||||
public boolean isAppInstalled(String packageName) {
|
public boolean isAppInstalled(String packageName) {
|
||||||
PackageManager pm = _context.getApplicationContext().getPackageManager();
|
|
||||||
try {
|
try {
|
||||||
|
PackageManager pm = _context.getApplicationContext().getPackageManager();
|
||||||
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
|
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
|
||||||
return true;
|
return true;
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
@ -409,17 +430,17 @@ public class ContextUtils {
|
||||||
* Restart the current app. Supply the class to start on startup
|
* Restart the current app. Supply the class to start on startup
|
||||||
*/
|
*/
|
||||||
public void restartApp(Class classToStart) {
|
public void restartApp(Class classToStart) {
|
||||||
Intent inte = new Intent(_context, classToStart);
|
Intent intent = new Intent(_context, classToStart);
|
||||||
PendingIntent inteP = PendingIntent.getActivity(_context, 555, inte, PendingIntent.FLAG_CANCEL_CURRENT);
|
PendingIntent pendi = PendingIntent.getActivity(_context, 555, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
AlarmManager mgr = (AlarmManager) _context.getSystemService(Context.ALARM_SERVICE);
|
AlarmManager mgr = (AlarmManager) _context.getSystemService(Context.ALARM_SERVICE);
|
||||||
if (_context instanceof Activity) {
|
if (_context instanceof Activity) {
|
||||||
((Activity) _context).finish();
|
((Activity) _context).finish();
|
||||||
}
|
}
|
||||||
if (mgr != null) {
|
if (mgr != null) {
|
||||||
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, inteP);
|
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendi);
|
||||||
} else {
|
} else {
|
||||||
inte.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||||
_context.startActivity(inte);
|
_context.startActivity(intent);
|
||||||
}
|
}
|
||||||
Runtime.getRuntime().exit(0);
|
Runtime.getRuntime().exit(0);
|
||||||
}
|
}
|
||||||
|
@ -488,19 +509,25 @@ public class ContextUtils {
|
||||||
* {@code androidLC} may be in any of the forms: en, de, de-rAt
|
* {@code androidLC} may be in any of the forms: en, de, de-rAt
|
||||||
* If given an empty string, the default (system) locale gets loaded
|
* If given an empty string, the default (system) locale gets loaded
|
||||||
*/
|
*/
|
||||||
public void setAppLanguage(String androidLC) {
|
public void setAppLanguage(final String androidLC) {
|
||||||
Locale locale = getLocaleByAndroidCode(androidLC);
|
Locale locale = getLocaleByAndroidCode(androidLC);
|
||||||
|
locale = (locale != null && !androidLC.isEmpty()) ? locale : Resources.getSystem().getConfiguration().locale;
|
||||||
|
setLocale(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContextUtils setLocale(final Locale locale) {
|
||||||
Configuration config = _context.getResources().getConfiguration();
|
Configuration config = _context.getResources().getConfiguration();
|
||||||
config.locale = (locale != null && !androidLC.isEmpty())
|
config.locale = (locale != null ? locale : Resources.getSystem().getConfiguration().locale);
|
||||||
? locale : Resources.getSystem().getConfiguration().locale;
|
|
||||||
_context.getResources().updateConfiguration(config, null);
|
_context.getResources().updateConfiguration(config, null);
|
||||||
|
Locale.setDefault(locale);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to guess if the color on top of the given {@code colorOnBottomInt}
|
* Try to guess if the color on top of the given {@code colorOnBottomInt}
|
||||||
* should be light or dark. Returns true if top color should be light
|
* should be light or dark. Returns true if top color should be light
|
||||||
*/
|
*/
|
||||||
public boolean shouldColorOnTopBeLight(@ColorInt int colorOnBottomInt) {
|
public boolean shouldColorOnTopBeLight(@ColorInt final int colorOnBottomInt) {
|
||||||
return 186 > (((0.299 * Color.red(colorOnBottomInt))
|
return 186 > (((0.299 * Color.red(colorOnBottomInt))
|
||||||
+ ((0.587 * Color.green(colorOnBottomInt))
|
+ ((0.587 * Color.green(colorOnBottomInt))
|
||||||
+ (0.114 * Color.blue(colorOnBottomInt)))));
|
+ (0.114 * Color.blue(colorOnBottomInt)))));
|
||||||
|
@ -509,7 +536,7 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Convert a html string to an android {@link Spanned} object
|
* Convert a html string to an android {@link Spanned} object
|
||||||
*/
|
*/
|
||||||
public Spanned htmlToSpanned(String html) {
|
public Spanned htmlToSpanned(final String html) {
|
||||||
Spanned result;
|
Spanned result;
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||||
result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
|
result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
|
||||||
|
@ -568,7 +595,7 @@ public class ContextUtils {
|
||||||
return dirs;
|
return dirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStorageName(File externalFileDir, boolean storageNameWithoutType) {
|
public String getStorageName(final File externalFileDir, final boolean storageNameWithoutType) {
|
||||||
boolean isInt = externalFileDir.getAbsolutePath().startsWith(Environment.getExternalStorageDirectory().getAbsolutePath());
|
boolean isInt = externalFileDir.getAbsolutePath().startsWith(Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||||
|
|
||||||
String[] split = externalFileDir.getAbsolutePath().split("/");
|
String[] split = externalFileDir.getAbsolutePath().split("/");
|
||||||
|
@ -579,7 +606,7 @@ public class ContextUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Pair<File, String>> getStorages(boolean internalStorageFolder, boolean sdcardFolders) {
|
public List<Pair<File, String>> getStorages(final boolean internalStorageFolder, final boolean sdcardFolders) {
|
||||||
List<Pair<File, String>> storages = new ArrayList<>();
|
List<Pair<File, String>> storages = new ArrayList<>();
|
||||||
for (Pair<File, String> pair : getAppDataPublicDirs(internalStorageFolder, sdcardFolders, true)) {
|
for (Pair<File, String> pair : getAppDataPublicDirs(internalStorageFolder, sdcardFolders, true)) {
|
||||||
if (pair.first != null && pair.first.getAbsolutePath().lastIndexOf("/Android/data") > 0) {
|
if (pair.first != null && pair.first.getAbsolutePath().lastIndexOf("/Android/data") > 0) {
|
||||||
|
@ -592,7 +619,7 @@ public class ContextUtils {
|
||||||
return storages;
|
return storages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getStorageRootFolder(File file) {
|
public File getStorageRootFolder(final File file) {
|
||||||
String filepath;
|
String filepath;
|
||||||
try {
|
try {
|
||||||
filepath = file.getCanonicalPath();
|
filepath = file.getCanonicalPath();
|
||||||
|
@ -613,7 +640,7 @@ public class ContextUtils {
|
||||||
*
|
*
|
||||||
* @param files Files and folders to scan
|
* @param files Files and folders to scan
|
||||||
*/
|
*/
|
||||||
public void mediaScannerScanFile(File... files) {
|
public void mediaScannerScanFile(final File... files) {
|
||||||
if (android.os.Build.VERSION.SDK_INT > 19) {
|
if (android.os.Build.VERSION.SDK_INT > 19) {
|
||||||
String[] paths = new String[files.length];
|
String[] paths = new String[files.length];
|
||||||
for (int i = 0; i < files.length; i++) {
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
@ -662,8 +689,12 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Get a {@link Bitmap} out of a {@link DrawableRes}
|
* Get a {@link Bitmap} out of a {@link DrawableRes}
|
||||||
*/
|
*/
|
||||||
public Bitmap drawableToBitmap(@DrawableRes int drawableId) {
|
public Bitmap drawableToBitmap(@DrawableRes final int drawableId) {
|
||||||
return drawableToBitmap(ContextCompat.getDrawable(_context, drawableId));
|
try {
|
||||||
|
return drawableToBitmap(ContextCompat.getDrawable(_context, drawableId));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -671,7 +702,7 @@ public class ContextUtils {
|
||||||
* Specifying a {@code maxDimen} is also possible and a value below 2000
|
* Specifying a {@code maxDimen} is also possible and a value below 2000
|
||||||
* is recommended, otherwise a {@link OutOfMemoryError} may occur
|
* is recommended, otherwise a {@link OutOfMemoryError} may occur
|
||||||
*/
|
*/
|
||||||
public Bitmap loadImageFromFilesystem(File imagePath, int maxDimen) {
|
public Bitmap loadImageFromFilesystem(final File imagePath, final int maxDimen) {
|
||||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||||
options.inJustDecodeBounds = true;
|
options.inJustDecodeBounds = true;
|
||||||
BitmapFactory.decodeFile(imagePath.getAbsolutePath(), options);
|
BitmapFactory.decodeFile(imagePath.getAbsolutePath(), options);
|
||||||
|
@ -687,7 +718,7 @@ public class ContextUtils {
|
||||||
* @param maxDimen Max size of the Bitmap (width or height)
|
* @param maxDimen Max size of the Bitmap (width or height)
|
||||||
* @return the scaling factor that needs to be applied to the bitmap
|
* @return the scaling factor that needs to be applied to the bitmap
|
||||||
*/
|
*/
|
||||||
public int calculateInSampleSize(BitmapFactory.Options options, int maxDimen) {
|
public int calculateInSampleSize(final BitmapFactory.Options options, final int maxDimen) {
|
||||||
// Raw height and width of image
|
// Raw height and width of image
|
||||||
int height = options.outHeight;
|
int height = options.outHeight;
|
||||||
int width = options.outWidth;
|
int width = options.outWidth;
|
||||||
|
@ -703,7 +734,7 @@ public class ContextUtils {
|
||||||
* Scale the bitmap so both dimensions are lower or equal to {@code maxDimen}
|
* Scale the bitmap so both dimensions are lower or equal to {@code maxDimen}
|
||||||
* This keeps the aspect ratio
|
* This keeps the aspect ratio
|
||||||
*/
|
*/
|
||||||
public Bitmap scaleBitmap(Bitmap bitmap, int maxDimen) {
|
public Bitmap scaleBitmap(final Bitmap bitmap, final int maxDimen) {
|
||||||
int picSize = Math.min(bitmap.getHeight(), bitmap.getWidth());
|
int picSize = Math.min(bitmap.getHeight(), bitmap.getWidth());
|
||||||
float scale = 1.f * maxDimen / picSize;
|
float scale = 1.f * maxDimen / picSize;
|
||||||
Matrix matrix = new Matrix();
|
Matrix matrix = new Matrix();
|
||||||
|
@ -714,7 +745,7 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Write the given {@link Bitmap} to {@code imageFile}, in {@link CompressFormat#JPEG} format
|
* Write the given {@link Bitmap} to {@code imageFile}, in {@link CompressFormat#JPEG} format
|
||||||
*/
|
*/
|
||||||
public boolean writeImageToFileJpeg(File imageFile, Bitmap image) {
|
public boolean writeImageToFileJpeg(final File imageFile, final Bitmap image) {
|
||||||
return writeImageToFile(imageFile, image, Bitmap.CompressFormat.JPEG, 95);
|
return writeImageToFile(imageFile, image, Bitmap.CompressFormat.JPEG, 95);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,7 +758,7 @@ public class ContextUtils {
|
||||||
* @param quality Quality level, defaults to 95
|
* @param quality Quality level, defaults to 95
|
||||||
* @return True if writing was successful
|
* @return True if writing was successful
|
||||||
*/
|
*/
|
||||||
public boolean writeImageToFile(File targetFile, Bitmap image, CompressFormat format, Integer quality) {
|
public boolean writeImageToFile(final File targetFile, final Bitmap image, CompressFormat format, Integer quality) {
|
||||||
File folder = new File(targetFile.getParent());
|
File folder = new File(targetFile.getParent());
|
||||||
if (quality == null || quality < 0 || quality > 100) {
|
if (quality == null || quality < 0 || quality > 100) {
|
||||||
quality = 95;
|
quality = 95;
|
||||||
|
@ -765,7 +796,7 @@ public class ContextUtils {
|
||||||
* Draw text in the center of the given {@link DrawableRes}
|
* Draw text in the center of the given {@link DrawableRes}
|
||||||
* This may be useful for e.g. badge counts
|
* This may be useful for e.g. badge counts
|
||||||
*/
|
*/
|
||||||
public Bitmap drawTextOnDrawable(@DrawableRes int drawableRes, String text, int textSize) {
|
public Bitmap drawTextOnDrawable(@DrawableRes final int drawableRes, final String text, final int textSize) {
|
||||||
Resources resources = _context.getResources();
|
Resources resources = _context.getResources();
|
||||||
float scale = resources.getDisplayMetrics().density;
|
float scale = resources.getDisplayMetrics().density;
|
||||||
Bitmap bitmap = drawableToBitmap(drawableRes);
|
Bitmap bitmap = drawableToBitmap(drawableRes);
|
||||||
|
@ -790,7 +821,7 @@ public class ContextUtils {
|
||||||
* Try to tint all {@link Menu}s {@link MenuItem}s with given color
|
* Try to tint all {@link Menu}s {@link MenuItem}s with given color
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
public void tintMenuItems(Menu menu, boolean recurse, @ColorInt int iconColor) {
|
public void tintMenuItems(final Menu menu, final boolean recurse, @ColorInt final int iconColor) {
|
||||||
for (int i = 0; i < menu.size(); i++) {
|
for (int i = 0; i < menu.size(); i++) {
|
||||||
MenuItem item = menu.getItem(i);
|
MenuItem item = menu.getItem(i);
|
||||||
try {
|
try {
|
||||||
|
@ -807,14 +838,14 @@ public class ContextUtils {
|
||||||
/**
|
/**
|
||||||
* Loads {@link Drawable} by given {@link DrawableRes} and applies a color
|
* Loads {@link Drawable} by given {@link DrawableRes} and applies a color
|
||||||
*/
|
*/
|
||||||
public Drawable tintDrawable(@DrawableRes int drawableRes, @ColorInt int color) {
|
public Drawable tintDrawable(@DrawableRes final int drawableRes, @ColorInt final int color) {
|
||||||
return tintDrawable(rdrawable(drawableRes), color);
|
return tintDrawable(rdrawable(drawableRes), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tint a {@link Drawable} with given {@code color}
|
* Tint a {@link Drawable} with given {@code color}
|
||||||
*/
|
*/
|
||||||
public Drawable tintDrawable(@Nullable Drawable drawable, @ColorInt int color) {
|
public Drawable tintDrawable(@Nullable Drawable drawable, @ColorInt final int color) {
|
||||||
if (drawable != null) {
|
if (drawable != null) {
|
||||||
drawable = DrawableCompat.wrap(drawable);
|
drawable = DrawableCompat.wrap(drawable);
|
||||||
DrawableCompat.setTint(drawable.mutate(), color);
|
DrawableCompat.setTint(drawable.mutate(), color);
|
||||||
|
@ -826,7 +857,10 @@ public class ContextUtils {
|
||||||
* Try to make icons in Toolbar/ActionBars SubMenus visible
|
* Try to make icons in Toolbar/ActionBars SubMenus visible
|
||||||
* This may not work on some devices and it maybe won't work on future android updates
|
* This may not work on some devices and it maybe won't work on future android updates
|
||||||
*/
|
*/
|
||||||
public void setSubMenuIconsVisiblity(Menu menu, boolean visible) {
|
public void setSubMenuIconsVisiblity(final Menu menu, final boolean visible) {
|
||||||
|
if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
|
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
|
||||||
try {
|
try {
|
||||||
@SuppressLint("PrivateApi") Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
|
@SuppressLint("PrivateApi") Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
|
||||||
|
@ -886,7 +920,7 @@ public class ContextUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getMimeType(File file) {
|
public String getMimeType(final File file) {
|
||||||
return getMimeType(Uri.fromFile(file));
|
return getMimeType(Uri.fromFile(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -895,7 +929,7 @@ public class ContextUtils {
|
||||||
* Android/Java's own MimeType map is very very small and detection barely works at all
|
* Android/Java's own MimeType map is very very small and detection barely works at all
|
||||||
* Hence use custom map for some file extensions
|
* Hence use custom map for some file extensions
|
||||||
*/
|
*/
|
||||||
public String getMimeType(Uri uri) {
|
public String getMimeType(final Uri uri) {
|
||||||
String mimeType = null;
|
String mimeType = null;
|
||||||
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
|
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
|
||||||
ContentResolver cr = _context.getContentResolver();
|
ContentResolver cr = _context.getContentResolver();
|
||||||
|
@ -936,7 +970,7 @@ public class ContextUtils {
|
||||||
return mimeType;
|
return mimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer parseColor(String colorstr) {
|
public Integer parseColor(final String colorstr) {
|
||||||
if (colorstr == null || colorstr.trim().isEmpty()) {
|
if (colorstr == null || colorstr.trim().isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -957,6 +991,22 @@ public class ContextUtils {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vibrate device one time by given amount of time, defaulting to 50ms
|
||||||
|
// Requires <uses-permission android:name="android.permission.VIBRATE" /> in AndroidManifest to work
|
||||||
|
@SuppressWarnings("UnnecessaryReturnStatement")
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
public void vibrate(final int... ms) {
|
||||||
|
int ms_v = ms != null && ms.length > 0 ? ms[0] : 50;
|
||||||
|
Vibrator vibrator = ((Vibrator) _context.getSystemService(VIBRATOR_SERVICE));
|
||||||
|
if (vibrator == null) {
|
||||||
|
return;
|
||||||
|
} else if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
vibrator.vibrate(VibrationEffect.createOneShot(ms_v, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||||
|
} else {
|
||||||
|
vibrator.vibrate(ms_v);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -240,6 +241,30 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean copyFile(final File src, final FileOutputStream os) {
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(src);
|
||||||
|
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,
|
// 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.
|
// the index of which needle was found in the contents of the file.
|
||||||
//
|
//
|
||||||
|
@ -452,7 +477,15 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
String[] units = abbreviation ? new String[]{"B", "kB", "MB", "GB", "TB"} : new String[]{"Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"};
|
String[] units = abbreviation ? new String[]{"B", "kB", "MB", "GB", "TB"} : new String[]{"Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"};
|
||||||
int unit = (int) (Math.log10(size) / Math.log10(1024));
|
int unit = (int) (Math.log10(size) / Math.log10(1024));
|
||||||
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, unit))
|
return new DecimalFormat("#,##0.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH)).format(size / Math.pow(1024, unit)) + " " + units[unit];
|
||||||
+ " " + units[unit];
|
}
|
||||||
|
|
||||||
|
public static int[] getTimeDiffHMS(long now, long past) {
|
||||||
|
int[] ret = new int[3];
|
||||||
|
long diff = Math.abs(now - past);
|
||||||
|
ret[0] = (int) (diff / (1000 * 60 * 60)); // hours
|
||||||
|
ret[1] = (int) (diff / (1000 * 60)) % 60; // min
|
||||||
|
ret[2] = (int) (diff / 1000) % 60; // sec
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ public class NetworkUtils {
|
||||||
int written = 0;
|
int written = 0;
|
||||||
final float invLength = 1f / connection.getContentLength();
|
final float invLength = 1f / connection.getContentLength();
|
||||||
|
|
||||||
byte data[] = new byte[BUFFER_SIZE];
|
byte[] data = new byte[BUFFER_SIZE];
|
||||||
while ((count = input.read(data)) != -1) {
|
while ((count = input.read(data)) != -1) {
|
||||||
output.write(data, 0, count);
|
output.write(data, 0, count);
|
||||||
if (invLength != -1f && progressCallback != null) {
|
if (invLength != -1f && progressCallback != null) {
|
||||||
|
|
|
@ -96,12 +96,12 @@ public class ShareUtil {
|
||||||
protected String _fileProviderAuthority;
|
protected String _fileProviderAuthority;
|
||||||
protected String _chooserTitle;
|
protected String _chooserTitle;
|
||||||
|
|
||||||
public ShareUtil(Context context) {
|
public ShareUtil(final Context context) {
|
||||||
_context = context;
|
_context = context;
|
||||||
_chooserTitle = "➥";
|
_chooserTitle = "➥";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContext(Context c) {
|
public void setContext(final Context c) {
|
||||||
_context = c;
|
_context = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +116,13 @@ public class ShareUtil {
|
||||||
return _fileProviderAuthority;
|
return _fileProviderAuthority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShareUtil setFileProviderAuthority(String fileProviderAuthority) {
|
public ShareUtil setFileProviderAuthority(final String fileProviderAuthority) {
|
||||||
_fileProviderAuthority = fileProviderAuthority;
|
_fileProviderAuthority = fileProviderAuthority;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ShareUtil setChooserTitle(String title) {
|
public ShareUtil setChooserTitle(final String title) {
|
||||||
_chooserTitle = title;
|
_chooserTitle = title;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ public class ShareUtil {
|
||||||
* @param file the file
|
* @param file the file
|
||||||
* @return Uri for this file
|
* @return Uri for this file
|
||||||
*/
|
*/
|
||||||
public Uri getUriByFileProviderAuthority(File file) {
|
public Uri getUriByFileProviderAuthority(final File file) {
|
||||||
return FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
return FileProvider.getUriForFile(_context, getFileProviderAuthority(), file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ public class ShareUtil {
|
||||||
* @param intent Thing to be shared
|
* @param intent Thing to be shared
|
||||||
* @param chooserText The title text for the chooser, or null for default
|
* @param chooserText The title text for the chooser, or null for default
|
||||||
*/
|
*/
|
||||||
public void showChooser(Intent intent, String chooserText) {
|
public void showChooser(final Intent intent, final String chooserText) {
|
||||||
_context.startActivity(Intent.createChooser(intent,
|
_context.startActivity(Intent.createChooser(intent,
|
||||||
chooserText != null ? chooserText : _chooserTitle));
|
chooserText != null ? chooserText : _chooserTitle));
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ public class ShareUtil {
|
||||||
* @param iconRes Icon resource for the item
|
* @param iconRes Icon resource for the item
|
||||||
* @param title Title of the item
|
* @param title Title of the item
|
||||||
*/
|
*/
|
||||||
public void createLauncherDesktopShortcut(Intent intent, @DrawableRes int iconRes, String title) {
|
public void createLauncherDesktopShortcut(final Intent intent, @DrawableRes final int iconRes, final String title) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
if (intent.getAction() == null) {
|
if (intent.getAction() == null) {
|
||||||
|
@ -182,7 +182,7 @@ public class ShareUtil {
|
||||||
* @param iconRes Icon resource for the item
|
* @param iconRes Icon resource for the item
|
||||||
* @param title Title of the item
|
* @param title Title of the item
|
||||||
*/
|
*/
|
||||||
public void createLauncherDesktopShortcutLegacy(Intent intent, @DrawableRes int iconRes, String title) {
|
public void createLauncherDesktopShortcutLegacy(final Intent intent, @DrawableRes final int iconRes, final String title) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
if (intent.getAction() == null) {
|
if (intent.getAction() == null) {
|
||||||
|
@ -203,7 +203,7 @@ public class ShareUtil {
|
||||||
* @param text The text to share
|
* @param text The text to share
|
||||||
* @param mimeType MimeType or null (uses text/plain)
|
* @param mimeType MimeType or null (uses text/plain)
|
||||||
*/
|
*/
|
||||||
public void shareText(String text, @Nullable String mimeType) {
|
public void shareText(final String text, @Nullable final String mimeType) {
|
||||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, text);
|
intent.putExtra(Intent.EXTRA_TEXT, text);
|
||||||
intent.setType(mimeType != null ? mimeType : MIME_TEXT_PLAIN);
|
intent.setType(mimeType != null ? mimeType : MIME_TEXT_PLAIN);
|
||||||
|
@ -216,7 +216,7 @@ public class ShareUtil {
|
||||||
* @param file The file to share
|
* @param file The file to share
|
||||||
* @param mimeType The files mime type
|
* @param mimeType The files mime type
|
||||||
*/
|
*/
|
||||||
public boolean shareStream(File file, String mimeType) {
|
public boolean shareStream(final File file, final String mimeType) {
|
||||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath());
|
intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath());
|
||||||
intent.setType(mimeType);
|
intent.setType(mimeType);
|
||||||
|
@ -237,7 +237,7 @@ public class ShareUtil {
|
||||||
* @param files The files to share
|
* @param files The files to share
|
||||||
* @param mimeType The files mime type. Usally * / * is the best option
|
* @param mimeType The files mime type. Usally * / * is the best option
|
||||||
*/
|
*/
|
||||||
public boolean shareStreamMultiple(Collection<File> files, String mimeType) {
|
public boolean shareStreamMultiple(final Collection<File> files, final String mimeType) {
|
||||||
ArrayList<Uri> uris = new ArrayList<>();
|
ArrayList<Uri> uris = new ArrayList<>();
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
File uri = new File(file.toString());
|
File uri = new File(file.toString());
|
||||||
|
@ -258,14 +258,13 @@ public class ShareUtil {
|
||||||
/**
|
/**
|
||||||
* Start calendar application to add new event, with given details prefilled
|
* Start calendar application to add new event, with given details prefilled
|
||||||
*/
|
*/
|
||||||
public boolean createCalendarAppointment(@Nullable String title, @Nullable String description, @Nullable String location, @Nullable Long... startAndEndTime) {
|
public boolean createCalendarAppointment(@Nullable final String title, @Nullable final String description, @Nullable final String location, @Nullable final Long... startAndEndTime) {
|
||||||
Intent intent = new Intent(Intent.ACTION_INSERT).setData(CalendarContract.Events.CONTENT_URI);
|
Intent intent = new Intent(Intent.ACTION_INSERT).setData(CalendarContract.Events.CONTENT_URI);
|
||||||
if (title != null) {
|
if (title != null) {
|
||||||
intent.putExtra(CalendarContract.Events.TITLE, title);
|
intent.putExtra(CalendarContract.Events.TITLE, title);
|
||||||
}
|
}
|
||||||
if (description != null) {
|
if (description != null) {
|
||||||
description = description.length() > 800 ? description.substring(0, 800) : description;
|
intent.putExtra(CalendarContract.Events.DESCRIPTION, (description.length() > 800 ? description.substring(0, 800) : description));
|
||||||
intent.putExtra(CalendarContract.Events.DESCRIPTION, description);
|
|
||||||
}
|
}
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
intent.putExtra(CalendarContract.Events.EVENT_LOCATION, location);
|
intent.putExtra(CalendarContract.Events.EVENT_LOCATION, location);
|
||||||
|
@ -292,7 +291,7 @@ public class ShareUtil {
|
||||||
*
|
*
|
||||||
* @param file The file to share
|
* @param file The file to share
|
||||||
*/
|
*/
|
||||||
public boolean viewFileInOtherApp(File file, @Nullable String type) {
|
public boolean viewFileInOtherApp(final File file, @Nullable final String type) {
|
||||||
// On some specific devices the first won't work
|
// On some specific devices the first won't work
|
||||||
Uri fileUri = null;
|
Uri fileUri = null;
|
||||||
try {
|
try {
|
||||||
|
@ -324,7 +323,7 @@ public class ShareUtil {
|
||||||
* @param format A {@link Bitmap.CompressFormat}, supporting JPEG,PNG,WEBP
|
* @param format A {@link Bitmap.CompressFormat}, supporting JPEG,PNG,WEBP
|
||||||
* @return if success, true
|
* @return if success, true
|
||||||
*/
|
*/
|
||||||
public boolean shareImage(Bitmap bitmap, Bitmap.CompressFormat format) {
|
public boolean shareImage(final Bitmap bitmap, final Bitmap.CompressFormat format) {
|
||||||
return shareImage(bitmap, format, 95, "SharedImage");
|
return shareImage(bitmap, format, 95, "SharedImage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,7 +336,7 @@ public class ShareUtil {
|
||||||
* @param quality Quality of the exported image [0-100]
|
* @param quality Quality of the exported image [0-100]
|
||||||
* @return if success, true
|
* @return if success, true
|
||||||
*/
|
*/
|
||||||
public boolean shareImage(Bitmap bitmap, Bitmap.CompressFormat format, int quality, String imageName) {
|
public boolean shareImage(final Bitmap bitmap, final Bitmap.CompressFormat format, final int quality, final String imageName) {
|
||||||
try {
|
try {
|
||||||
String ext = format.name().toLowerCase();
|
String ext = format.name().toLowerCase();
|
||||||
File file = File.createTempFile(imageName, "." + ext.replace("jpeg", "jpg"), _context.getExternalCacheDir());
|
File file = File.createTempFile(imageName, "." + ext.replace("jpeg", "jpg"), _context.getExternalCacheDir());
|
||||||
|
@ -359,19 +358,23 @@ public class ShareUtil {
|
||||||
* @return {{@link PrintJob}} or null
|
* @return {{@link PrintJob}} or null
|
||||||
*/
|
*/
|
||||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||||
@SuppressWarnings("deprecation")
|
public PrintJob print(final WebView webview, final String jobName, final boolean... landscape) {
|
||||||
public PrintJob print(WebView webview, String jobName) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
PrintDocumentAdapter printAdapter;
|
final PrintDocumentAdapter printAdapter;
|
||||||
PrintManager printManager = (PrintManager) _context.getSystemService(Context.PRINT_SERVICE);
|
final PrintManager printManager = (PrintManager) _context.getSystemService(Context.PRINT_SERVICE);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
printAdapter = webview.createPrintDocumentAdapter(jobName);
|
printAdapter = webview.createPrintDocumentAdapter(jobName);
|
||||||
} else {
|
} else {
|
||||||
printAdapter = webview.createPrintDocumentAdapter();
|
printAdapter = webview.createPrintDocumentAdapter();
|
||||||
}
|
}
|
||||||
|
final PrintAttributes.Builder attrib = new PrintAttributes.Builder();
|
||||||
|
if (landscape != null && landscape.length > 0 && landscape[0]) {
|
||||||
|
attrib.setMediaSize(new PrintAttributes.MediaSize("ISO_A4", "android", 11690, 8270));
|
||||||
|
attrib.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0));
|
||||||
|
}
|
||||||
if (printManager != null) {
|
if (printManager != null) {
|
||||||
try {
|
try {
|
||||||
return printManager.print(jobName, printAdapter, new PrintAttributes.Builder().build());
|
return printManager.print(jobName, printAdapter, attrib.build());
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,8 +389,7 @@ public class ShareUtil {
|
||||||
* See {@link #print(WebView, String) print method}
|
* See {@link #print(WebView, String) print method}
|
||||||
*/
|
*/
|
||||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||||
@SuppressWarnings("deprecation")
|
public PrintJob createPdf(final WebView webview, final String jobName) {
|
||||||
public PrintJob createPdf(WebView webview, String jobName) {
|
|
||||||
return print(webview, jobName);
|
return print(webview, jobName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +401,7 @@ public class ShareUtil {
|
||||||
* @return A {@link Bitmap} or null
|
* @return A {@link Bitmap} or null
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Bitmap getBitmapFromWebView(WebView webView) {
|
public static Bitmap getBitmapFromWebView(final WebView webView) {
|
||||||
try {
|
try {
|
||||||
//Measure WebView's content
|
//Measure WebView's content
|
||||||
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
||||||
|
@ -432,7 +434,7 @@ public class ShareUtil {
|
||||||
* Replace (primary) clipboard contents with given {@code text}
|
* Replace (primary) clipboard contents with given {@code text}
|
||||||
* @param text Text to be set
|
* @param text Text to be set
|
||||||
*/
|
*/
|
||||||
public boolean setClipboard(CharSequence text) {
|
public boolean setClipboard(final CharSequence text) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||||
android.text.ClipboardManager cm = ((android.text.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE));
|
android.text.ClipboardManager cm = ((android.text.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE));
|
||||||
if (cm != null) {
|
if (cm != null) {
|
||||||
|
@ -485,7 +487,7 @@ public class ShareUtil {
|
||||||
* @param callback Callback after paste try
|
* @param callback Callback after paste try
|
||||||
* @param serverOrNothing Supply one or no hastebin server. If empty, the default gets taken
|
* @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) {
|
public void pasteOnHastebin(final String text, final Callback.a2<Boolean, String> callback, final String... serverOrNothing) {
|
||||||
final Handler handler = new Handler();
|
final Handler handler = new Handler();
|
||||||
final String server = (serverOrNothing != null && serverOrNothing.length > 0 && serverOrNothing[0] != null)
|
final String server = (serverOrNothing != null && serverOrNothing.length > 0 && serverOrNothing[0] != null)
|
||||||
? serverOrNothing[0] : "https://hastebin.com";
|
? serverOrNothing[0] : "https://hastebin.com";
|
||||||
|
@ -507,7 +509,7 @@ public class ShareUtil {
|
||||||
* @param body Body (content) 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
|
* @param to recipients to be prefilled in the mail
|
||||||
*/
|
*/
|
||||||
public void draftEmail(String subject, String body, String... to) {
|
public void draftEmail(final String subject, final String body, final String... to) {
|
||||||
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
||||||
intent.setData(Uri.parse("mailto:"));
|
intent.setData(Uri.parse("mailto:"));
|
||||||
if (subject != null) {
|
if (subject != null) {
|
||||||
|
@ -528,7 +530,7 @@ public class ShareUtil {
|
||||||
* @param receivingIntent The intent from {@link Activity#getIntent()}
|
* @param receivingIntent The intent from {@link Activity#getIntent()}
|
||||||
* @return A file or null if extraction did not succeed
|
* @return A file or null if extraction did not succeed
|
||||||
*/
|
*/
|
||||||
public File extractFileFromIntent(Intent receivingIntent) {
|
public File extractFileFromIntent(final Intent receivingIntent) {
|
||||||
String action = receivingIntent.getAction();
|
String action = receivingIntent.getAction();
|
||||||
String type = receivingIntent.getType();
|
String type = receivingIntent.getType();
|
||||||
File tmpf;
|
File tmpf;
|
||||||
|
@ -572,6 +574,14 @@ public class ShareUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// media/ prefix for External storage
|
||||||
|
if (fileStr.startsWith((tmps = "media/"))) {
|
||||||
|
File f = new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileStr.substring(tmps.length())));
|
||||||
|
if (f.exists()) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Next/OwnCloud Fileprovider
|
// Next/OwnCloud Fileprovider
|
||||||
for (String fp : new String[]{"org.nextcloud.files", "org.nextcloud.beta.files", "org.owncloud.files"}) {
|
for (String fp : new String[]{"org.nextcloud.files", "org.nextcloud.beta.files", "org.owncloud.files"}) {
|
||||||
if (fileProvider.equals(fp) && fileStr.startsWith(tmps = "external_files/")) {
|
if (fileProvider.equals(fp) && fileStr.startsWith(tmps = "external_files/")) {
|
||||||
|
@ -587,6 +597,16 @@ public class ShareUtil {
|
||||||
return new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + fileStr.substring(tmps.length())));
|
return new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + fileStr.substring(tmps.length())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fileStr.startsWith(tmps = "external_files/")) {
|
||||||
|
for (String prefix : new String[]{Environment.getExternalStorageDirectory().getAbsolutePath(), "/storage", ""}) {
|
||||||
|
File f = new File(Uri.decode(prefix + "/" + fileStr.substring(tmps.length())));
|
||||||
|
if (f.exists()) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// URI Encoded paths with full path after content://package/
|
// URI Encoded paths with full path after content://package/
|
||||||
if (fileStr.startsWith("/") || fileStr.startsWith("%2F")) {
|
if (fileStr.startsWith("/") || fileStr.startsWith("%2F")) {
|
||||||
tmpf = new File(Uri.decode(fileStr));
|
tmpf = new File(Uri.decode(fileStr));
|
||||||
|
@ -624,6 +644,11 @@ public class ShareUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String extractFileFromIntentStr(final Intent receivingIntent) {
|
||||||
|
File f = extractFileFromIntent(receivingIntent);
|
||||||
|
return f != null ? f.getAbsolutePath() : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request a picture from camera-like apps
|
* Request a picture from camera-like apps
|
||||||
* Result ({@link String}) will be available from {@link Activity#onActivityResult(int, int, Intent)}.
|
* Result ({@link String}) will be available from {@link Activity#onActivityResult(int, int, Intent)}.
|
||||||
|
@ -634,7 +659,8 @@ public class ShareUtil {
|
||||||
*
|
*
|
||||||
* @param target Path to file to write to, if folder the filename gets app_name + millis + random filename. If null DCIM folder is used.
|
* @param target Path to file to write to, if folder the filename gets app_name + millis + random filename. If null DCIM folder is used.
|
||||||
*/
|
*/
|
||||||
public String requestCameraPicture(File target) {
|
@SuppressWarnings("RegExpRedundantEscape")
|
||||||
|
public String requestCameraPicture(final File target) {
|
||||||
if (!(_context instanceof Activity)) {
|
if (!(_context instanceof Activity)) {
|
||||||
throw new RuntimeException("Error: ShareUtil.requestCameraPicture needs an Activity Context.");
|
throw new RuntimeException("Error: ShareUtil.requestCameraPicture needs an Activity Context.");
|
||||||
}
|
}
|
||||||
|
@ -647,7 +673,7 @@ public class ShareUtil {
|
||||||
if (target != null && !target.isDirectory()) {
|
if (target != null && !target.isDirectory()) {
|
||||||
photoFile = target;
|
photoFile = target;
|
||||||
} else {
|
} else {
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.getDefault());
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.ENGLISH);
|
||||||
File storageDir = target != null ? target : new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Camera");
|
File storageDir = target != null ? target : new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Camera");
|
||||||
String imageFileName = ((new ContextUtils(_context).rstr("app_name")).replaceAll("[^a-zA-Z0-9\\.\\-]", "_") + "_").replace("__", "_") + sdf.format(new Date());
|
String imageFileName = ((new ContextUtils(_context).rstr("app_name")).replaceAll("[^a-zA-Z0-9\\.\\-]", "_") + "_").replace("__", "_") + sdf.format(new Date());
|
||||||
photoFile = new File(storageDir, imageFileName + ".jpg");
|
photoFile = new File(storageDir, imageFileName + ".jpg");
|
||||||
|
@ -686,7 +712,7 @@ public class ShareUtil {
|
||||||
* Also may forward results via local broadcast
|
* Also may forward results via local broadcast
|
||||||
*/
|
*/
|
||||||
@SuppressLint("ApplySharedPref")
|
@SuppressLint("ApplySharedPref")
|
||||||
public Object extractResultFromActivityResult(int requestCode, int resultCode, Intent data, Activity... activityOrNull) {
|
public Object extractResultFromActivityResult(final int requestCode, final int resultCode, final Intent data, final Activity... activityOrNull) {
|
||||||
Activity activity = greedyGetActivity(activityOrNull);
|
Activity activity = greedyGetActivity(activityOrNull);
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case REQUEST_CAMERA_PICTURE: {
|
case REQUEST_CAMERA_PICTURE: {
|
||||||
|
@ -717,6 +743,10 @@ public class ShareUtil {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to grab via file extraction method
|
||||||
|
data.setAction(Intent.ACTION_VIEW);
|
||||||
|
picturePath = picturePath != null ? picturePath : extractFileFromIntentStr(data);
|
||||||
|
|
||||||
// Retrieve image from file descriptor / Cloud, e.g.: Google Drive, Picasa
|
// Retrieve image from file descriptor / Cloud, e.g.: Google Drive, Picasa
|
||||||
if (picturePath == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (picturePath == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
try {
|
try {
|
||||||
|
@ -762,7 +792,7 @@ public class ShareUtil {
|
||||||
* Send a local broadcast (to receive within app), with given action and string-extra+value.
|
* Send a local broadcast (to receive within app), with given action and string-extra+value.
|
||||||
* This is a convenience method for quickly sending just one thing.
|
* This is a convenience method for quickly sending just one thing.
|
||||||
*/
|
*/
|
||||||
public void sendLocalBroadcastWithStringExtra(String action, String extra, CharSequence value) {
|
public void sendLocalBroadcastWithStringExtra(final String action, final String extra, final CharSequence value) {
|
||||||
Intent intent = new Intent(action);
|
Intent intent = new Intent(action);
|
||||||
intent.putExtra(extra, value);
|
intent.putExtra(extra, value);
|
||||||
LocalBroadcastManager.getInstance(_context).sendBroadcast(intent);
|
LocalBroadcastManager.getInstance(_context).sendBroadcast(intent);
|
||||||
|
@ -776,7 +806,7 @@ public class ShareUtil {
|
||||||
* @param filterActions All {@link IntentFilter} actions to filter for
|
* @param filterActions All {@link IntentFilter} actions to filter for
|
||||||
* @return The created instance. Has to be unregistered on {@link Activity} lifecycle events.
|
* @return The created instance. Has to be unregistered on {@link Activity} lifecycle events.
|
||||||
*/
|
*/
|
||||||
public BroadcastReceiver receiveResultFromLocalBroadcast(Callback.a2<Intent, BroadcastReceiver> callback, boolean autoUnregister, String... filterActions) {
|
public BroadcastReceiver receiveResultFromLocalBroadcast(final Callback.a2<Intent, BroadcastReceiver> callback, final boolean autoUnregister, final String... filterActions) {
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
IntentFilter intentFilter = new IntentFilter();
|
||||||
for (String filterAction : filterActions) {
|
for (String filterAction : filterActions) {
|
||||||
intentFilter.addAction(filterAction);
|
intentFilter.addAction(filterAction);
|
||||||
|
@ -804,7 +834,7 @@ public class ShareUtil {
|
||||||
*
|
*
|
||||||
* @param file File that should be edited
|
* @param file File that should be edited
|
||||||
*/
|
*/
|
||||||
public void requestPictureEdit(File file) {
|
public void requestPictureEdit(final File file) {
|
||||||
Uri uri = getUriByFileProviderAuthority(file);
|
Uri uri = getUriByFileProviderAuthority(file);
|
||||||
int flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
int flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||||
|
|
||||||
|
@ -826,9 +856,10 @@ public class ShareUtil {
|
||||||
*
|
*
|
||||||
* @param file Target file
|
* @param file Target file
|
||||||
* @param mode 1 for picture, 2 for video, anything else for other
|
* @param mode 1 for picture, 2 for video, anything else for other
|
||||||
* @return
|
* @return Media URI
|
||||||
*/
|
*/
|
||||||
public Uri getMediaUri(File file, int mode) {
|
@SuppressWarnings("TryFinallyCanBeTryWithResources")
|
||||||
|
public Uri getMediaUri(final File file, final int mode) {
|
||||||
Uri uri = MediaStore.Files.getContentUri("external");
|
Uri uri = MediaStore.Files.getContentUri("external");
|
||||||
uri = (mode != 0) ? (mode == 1 ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI) : uri;
|
uri = (mode != 0) ? (mode == 1 ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI) : uri;
|
||||||
|
|
||||||
|
@ -854,7 +885,7 @@ public class ShareUtil {
|
||||||
* which implement the Chrome Custom Tab interface. This method changes
|
* which implement the Chrome Custom Tab interface. This method changes
|
||||||
* the customtab intent to use an available compatible browser, if available.
|
* the customtab intent to use an available compatible browser, if available.
|
||||||
*/
|
*/
|
||||||
public void enableChromeCustomTabsForOtherBrowsers(Intent customTabIntent) {
|
public void enableChromeCustomTabsForOtherBrowsers(final Intent customTabIntent) {
|
||||||
String[] checkpkgs = new String[]{
|
String[] checkpkgs = new String[]{
|
||||||
"com.android.chrome", "com.chrome.beta", "com.chrome.dev", "com.google.android.apps.chrome", "org.chromium.chrome",
|
"com.android.chrome", "com.chrome.beta", "com.chrome.dev", "com.google.android.apps.chrome", "org.chromium.chrome",
|
||||||
"org.mozilla.fennec_fdroid", "org.mozilla.firefox", "org.mozilla.firefox_beta", "org.mozilla.fennec_aurora",
|
"org.mozilla.fennec_fdroid", "org.mozilla.firefox", "org.mozilla.firefox_beta", "org.mozilla.fennec_aurora",
|
||||||
|
@ -905,7 +936,7 @@ public class ShareUtil {
|
||||||
* Request storage access. The user needs to press "Select storage" at the correct storage.
|
* Request storage access. The user needs to press "Select storage" at the correct storage.
|
||||||
* @param activity The activity which will receive the result from startActivityForResult
|
* @param activity The activity which will receive the result from startActivityForResult
|
||||||
*/
|
*/
|
||||||
public void requestStorageAccessFramework(Activity... activity) {
|
public void requestStorageAccessFramework(final Activity... activity) {
|
||||||
Activity a = greedyGetActivity(activity);
|
Activity a = greedyGetActivity(activity);
|
||||||
if (a != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
if (a != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
|
@ -961,8 +992,12 @@ public class ShareUtil {
|
||||||
* @param file The file object (file/folder)
|
* @param file The file object (file/folder)
|
||||||
* @return Wether or not the file is under storage access folder
|
* @return Wether or not the file is under storage access folder
|
||||||
*/
|
*/
|
||||||
public boolean isUnderStorageAccessFolder(File file) {
|
public boolean isUnderStorageAccessFolder(final File file) {
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
|
// When file writeable as is, it's the fastest way to learn SAF isn't required
|
||||||
|
if (file.canWrite()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ContextUtils cu = new ContextUtils(_context);
|
ContextUtils cu = new ContextUtils(_context);
|
||||||
for (Pair<File, String> storage : cu.getStorages(false, true)) {
|
for (Pair<File, String> storage : cu.getStorages(false, true)) {
|
||||||
if (file.getAbsolutePath().startsWith(storage.first.getAbsolutePath())) {
|
if (file.getAbsolutePath().startsWith(storage.first.getAbsolutePath())) {
|
||||||
|
@ -978,7 +1013,7 @@ public class ShareUtil {
|
||||||
/**
|
/**
|
||||||
* Greedy extract Activity from parameter or convert context if it's a activity
|
* Greedy extract Activity from parameter or convert context if it's a activity
|
||||||
*/
|
*/
|
||||||
private Activity greedyGetActivity(Activity... activity) {
|
private Activity greedyGetActivity(final Activity... activity) {
|
||||||
if (activity != null && activity.length != 0 && activity[0] != null) {
|
if (activity != null && activity.length != 0 && activity[0] != null) {
|
||||||
return activity[0];
|
return activity[0];
|
||||||
}
|
}
|
||||||
|
@ -996,10 +1031,11 @@ public class ShareUtil {
|
||||||
* @param isDir Wether or not the given file parameter is a directory
|
* @param isDir Wether or not the given file parameter is a directory
|
||||||
* @return Wether or not the file can be written
|
* @return Wether or not the file can be written
|
||||||
*/
|
*/
|
||||||
public boolean canWriteFile(File file, boolean isDir) {
|
public boolean canWriteFile(final File file, final boolean isDir) {
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
return false;
|
return false;
|
||||||
} else if (file.getAbsolutePath().startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
|
} else if (file.getAbsolutePath().startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())
|
||||||
|
|| file.getAbsolutePath().startsWith(_context.getFilesDir().getAbsolutePath())) {
|
||||||
boolean s1 = isDir && file.getParentFile().canWrite();
|
boolean s1 = isDir && file.getParentFile().canWrite();
|
||||||
return !isDir && file.getParentFile() != null ? file.getParentFile().canWrite() : file.canWrite();
|
return !isDir && file.getParentFile() != null ? file.getParentFile().canWrite() : file.canWrite();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1017,7 +1053,8 @@ public class ShareUtil {
|
||||||
* @param isDir Wether or not file is a directory. For non-existing (to be created) files this info is not known hence required.
|
* @param isDir Wether or not file is a directory. For non-existing (to be created) files this info is not known hence required.
|
||||||
* @return A {@link DocumentFile} object or null if file cannot be converted
|
* @return A {@link DocumentFile} object or null if file cannot be converted
|
||||||
*/
|
*/
|
||||||
public DocumentFile getDocumentFile(File file, boolean isDir) {
|
@SuppressWarnings("RegExpRedundantEscape")
|
||||||
|
public DocumentFile getDocumentFile(final File file, final boolean isDir) {
|
||||||
// On older versions use fromFile
|
// On older versions use fromFile
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
|
||||||
return DocumentFile.fromFile(file);
|
return DocumentFile.fromFile(file);
|
||||||
|
@ -1066,7 +1103,7 @@ public class ShareUtil {
|
||||||
return dof;
|
return dof;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showMountSdDialog(@StringRes int title, @StringRes int description, @DrawableRes int mountDescriptionGraphic, Activity... activityOrNull) {
|
public void showMountSdDialog(@StringRes final int title, @StringRes final int description, @DrawableRes final int mountDescriptionGraphic, final Activity... activityOrNull) {
|
||||||
Activity activity = greedyGetActivity(activityOrNull);
|
Activity activity = greedyGetActivity(activityOrNull);
|
||||||
if (activity == null) {
|
if (activity == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -1087,11 +1124,12 @@ public class ShareUtil {
|
||||||
dialogi.show();
|
dialogi.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeFile(File file, boolean isDirectory, Callback.a2<Boolean, FileOutputStream> writeFileCallback) {
|
@SuppressWarnings({"ResultOfMethodCallIgnored", "StatementWithEmptyBody"})
|
||||||
|
public void writeFile(final File file, final boolean isDirectory, final Callback.a2<Boolean, FileOutputStream> writeFileCallback) {
|
||||||
try {
|
try {
|
||||||
FileOutputStream fileOutputStream = null;
|
FileOutputStream fileOutputStream = null;
|
||||||
ParcelFileDescriptor pfd = null;
|
ParcelFileDescriptor pfd = null;
|
||||||
if (file.canWrite()) {
|
if (file.canWrite() || (!file.exists() && file.getParentFile().canWrite())) {
|
||||||
if (isDirectory) {
|
if (isDirectory) {
|
||||||
file.mkdirs();
|
file.mkdirs();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1112,7 +1150,10 @@ public class ShareUtil {
|
||||||
writeFileCallback.callback(fileOutputStream != null || (isDirectory && file.exists()), fileOutputStream);
|
writeFileCallback.callback(fileOutputStream != null || (isDirectory && file.exists()), fileOutputStream);
|
||||||
}
|
}
|
||||||
if (fileOutputStream != null) {
|
if (fileOutputStream != null) {
|
||||||
fileOutputStream.close();
|
try {
|
||||||
|
fileOutputStream.close();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (pfd != null) {
|
if (pfd != null) {
|
||||||
pfd.close();
|
pfd.close();
|
||||||
|
@ -1132,7 +1173,7 @@ public class ShareUtil {
|
||||||
* @param directCall Direct call number if possible
|
* @param directCall Direct call number if possible
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("SimplifiableConditionalExpression")
|
@SuppressWarnings("SimplifiableConditionalExpression")
|
||||||
public void callTelephoneNumber(String telNo, boolean... directCall) {
|
public void callTelephoneNumber(final String telNo, final boolean... directCall) {
|
||||||
Activity activity = greedyGetActivity();
|
Activity activity = greedyGetActivity();
|
||||||
if (activity == null) {
|
if (activity == null) {
|
||||||
throw new RuntimeException("Error: ShareUtil::callTelephoneNumber needs to be contstructed with activity context");
|
throw new RuntimeException("Error: ShareUtil::callTelephoneNumber needs to be contstructed with activity context");
|
||||||
|
|
|
@ -13,8 +13,8 @@ import java.text.SimpleDateFormat
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
version_gradle_tools = "3.5.1"
|
version_gradle_tools = "3.5.2"
|
||||||
version_plugin_kotlin = "1.3.50"
|
version_plugin_kotlin = "1.3.60"
|
||||||
enable_plugin_kotlin = false
|
enable_plugin_kotlin = false
|
||||||
|
|
||||||
version_compileSdk = 28
|
version_compileSdk = 28
|
||||||
|
|
Loading…
Reference in a new issue