mirror of
https://github.com/gsantner/dandelion
synced 2024-11-21 20:02:07 +01:00
Update gsantner-opoc to latest state
This commit is contained in:
parent
43a2ad25bc
commit
586875e32b
5 changed files with 233 additions and 174 deletions
|
@ -26,7 +26,7 @@ import com.github.dfa.diaspora_android.data.DiasporaAspect;
|
|||
import com.github.dfa.diaspora_android.data.DiasporaPodList.DiasporaPod;
|
||||
import com.github.dfa.diaspora_android.web.ProxyHandler;
|
||||
|
||||
import net.gsantner.opoc.util.AppSettingsBase;
|
||||
import net.gsantner.opoc.preference.SharedPreferencesPropertyBackend;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -38,7 +38,7 @@ import java.util.List;
|
|||
* Created by gsantner (http://gsantner.net/) on 20.03.16. Part of dandelion*.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public class AppSettings extends AppSettingsBase {
|
||||
public class AppSettings extends SharedPreferencesPropertyBackend {
|
||||
private final SharedPreferences _prefPod;
|
||||
private DiasporaPod currentPod0Cached;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import java.io.InputStreamReader;
|
|||
/**
|
||||
* Simple Markdown Parser
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "CaughtExceptionImmediatelyRethrown", "SameParameterValue", "unused", "SpellCheckingInspection", "RepeatedSpace", "SingleCharAlternation"})
|
||||
@SuppressWarnings({"WeakerAccess", "CaughtExceptionImmediatelyRethrown", "SameParameterValue", "unused", "SpellCheckingInspection", "RepeatedSpace", "SingleCharAlternation", "Convert2Lambda"})
|
||||
public class SimpleMarkdownParser {
|
||||
//########################
|
||||
//## Statics
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
#########################################################*/
|
||||
package net.gsantner.opoc.util;
|
||||
package net.gsantner.opoc.preference;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings({"UnusedReturnValue", "SpellCheckingInspection"})
|
||||
@SuppressWarnings({"UnusedReturnValue", "SpellCheckingInspection", "unused", "SameParameterValue"})
|
||||
public interface PropertyBackend<TKEY, TTHIS> {
|
||||
String getString(TKEY key, String defaultValue);
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
}
|
||||
*/
|
||||
|
||||
package net.gsantner.opoc.util;
|
||||
package net.gsantner.opoc.preference;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
|
@ -48,36 +48,36 @@ import java.util.List;
|
|||
|
||||
|
||||
/**
|
||||
* Wrapper for settings based on SharedPreferences with keys in resources
|
||||
* Wrapper for settings based on SharedPreferences, optionally with keys in resources
|
||||
* Default SharedPreference (_prefApp) will be taken if no SP is specified, else the first one
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SpellCheckingInspection", "SameParameterValue"})
|
||||
public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase> {
|
||||
public class SharedPreferencesPropertyBackend implements PropertyBackend<String, SharedPreferencesPropertyBackend> {
|
||||
protected static final String ARRAY_SEPARATOR = "%%%";
|
||||
protected static final String ARRAY_SEPARATOR_SUBSTITUTE = "§§§";
|
||||
public static final String SHARED_PREF_APP = "app";
|
||||
|
||||
//########################
|
||||
//## Members, Constructors
|
||||
//########################
|
||||
//
|
||||
// Members, Constructors
|
||||
//
|
||||
protected final SharedPreferences _prefApp;
|
||||
protected final String _prefAppName;
|
||||
protected final Context _context;
|
||||
|
||||
public AppSettingsBase(final Context context) {
|
||||
public SharedPreferencesPropertyBackend(final Context context) {
|
||||
this(context, SHARED_PREF_APP);
|
||||
}
|
||||
|
||||
public AppSettingsBase(final Context context, final String prefAppName) {
|
||||
public SharedPreferencesPropertyBackend(final Context context, final String prefAppName) {
|
||||
_context = context.getApplicationContext();
|
||||
_prefAppName = TextUtils.isEmpty(prefAppName) ?
|
||||
_context.getPackageName() + "_preferences" : prefAppName;
|
||||
_prefApp = _context.getSharedPreferences(_prefAppName, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
//#####################
|
||||
//## Methods
|
||||
//#####################
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
public Context getContext() {
|
||||
return _context;
|
||||
}
|
||||
|
@ -136,9 +136,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
return (pref != null && pref.length > 0 ? pref[0] : _prefApp);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter for resources
|
||||
//#################################
|
||||
//
|
||||
// Getter for resources
|
||||
//
|
||||
public String rstr(@StringRes int stringKeyResourceId) {
|
||||
return _context.getString(stringKeyResourceId);
|
||||
}
|
||||
|
@ -148,9 +148,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
}
|
||||
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for String
|
||||
//#################################
|
||||
//
|
||||
// Getter & Setter for String
|
||||
//
|
||||
public void setString(@StringRes int keyResourceId, String value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putString(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
@ -235,9 +235,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
return getStringListOne(key, gp(pref));
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for integer
|
||||
//#################################
|
||||
//
|
||||
// Getter & Setter for integer
|
||||
//
|
||||
public void setInt(@StringRes int keyResourceId, int value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putInt(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
@ -319,9 +319,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
}
|
||||
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Long
|
||||
//#################################
|
||||
//
|
||||
// Getter & Setter for Long
|
||||
//
|
||||
public void setLong(@StringRes int keyResourceId, long value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putLong(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
@ -338,9 +338,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
return gp(pref).getLong(key, defaultValue);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Float
|
||||
//#################################
|
||||
//
|
||||
// Getter & Setter for Float
|
||||
//
|
||||
public void setFloat(@StringRes int keyResourceId, float value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putFloat(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
@ -357,9 +357,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
return gp(pref).getFloat(key, defaultValue);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Double
|
||||
//#################################
|
||||
//
|
||||
// Getter & Setter for Double
|
||||
//
|
||||
public void setDouble(@StringRes int keyResourceId, double value, final SharedPreferences... pref) {
|
||||
setLong(rstr(keyResourceId), Double.doubleToRawLongBits(value));
|
||||
}
|
||||
|
@ -376,9 +376,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
return Double.longBitsToDouble(getLong(key, Double.doubleToRawLongBits(defaultValue), gp(pref)));
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for boolean
|
||||
//#################################
|
||||
//
|
||||
// Getter & Setter for boolean
|
||||
//
|
||||
public void setBool(@StringRes int keyResourceId, boolean value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putBoolean(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
@ -395,9 +395,9 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
return gp(pref).getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Color
|
||||
//#################################
|
||||
//
|
||||
// Getter & Setter for Color
|
||||
//
|
||||
public int getColor(String key, @ColorRes int defaultColor, final SharedPreferences... pref) {
|
||||
return gp(pref).getInt(key, rcolor(defaultColor));
|
||||
}
|
||||
|
@ -450,49 +450,49 @@ public class AppSettingsBase implements PropertyBackend<String, AppSettingsBase>
|
|||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setString(String key, String value) {
|
||||
public SharedPreferencesPropertyBackend setString(String key, String value) {
|
||||
setString(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setInt(String key, int value) {
|
||||
public SharedPreferencesPropertyBackend setInt(String key, int value) {
|
||||
setInt(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setLong(String key, long value) {
|
||||
public SharedPreferencesPropertyBackend setLong(String key, long value) {
|
||||
setLong(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setBool(String key, boolean value) {
|
||||
public SharedPreferencesPropertyBackend setBool(String key, boolean value) {
|
||||
setBool(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setFloat(String key, float value) {
|
||||
public SharedPreferencesPropertyBackend setFloat(String key, float value) {
|
||||
setFloat(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setDouble(String key, double value) {
|
||||
public SharedPreferencesPropertyBackend setDouble(String key, double value) {
|
||||
setDouble(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setIntList(String key, List<Integer> value) {
|
||||
public SharedPreferencesPropertyBackend setIntList(String key, List<Integer> value) {
|
||||
setIntListOne(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppSettingsBase setStringList(String key, List<String> value) {
|
||||
public SharedPreferencesPropertyBackend setStringList(String key, List<String> value) {
|
||||
setStringListOne(key, value, _prefApp);
|
||||
return this;
|
||||
}
|
|
@ -14,7 +14,6 @@ import android.annotation.SuppressLint;
|
|||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
|
@ -28,6 +27,7 @@ import android.graphics.Color;
|
|||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.VectorDrawable;
|
||||
|
@ -65,8 +65,6 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
|
@ -74,9 +72,9 @@ import static android.graphics.Bitmap.CompressFormat;
|
|||
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "ObsoleteSdkInt", "deprecation", "SpellCheckingInspection"})
|
||||
public class ContextUtils {
|
||||
//########################
|
||||
//## Members, Constructors
|
||||
//########################
|
||||
//
|
||||
// Members, Constructors
|
||||
//
|
||||
protected Context _context;
|
||||
|
||||
public ContextUtils(Context context) {
|
||||
|
@ -87,57 +85,81 @@ public class ContextUtils {
|
|||
return _context;
|
||||
}
|
||||
|
||||
//########################
|
||||
//## Resources
|
||||
//########################
|
||||
static class ResType {
|
||||
public static final String DRAWABLE = "drawable";
|
||||
public static final String STRING = "string";
|
||||
public static final String PLURAL = "plural";
|
||||
public static final String COLOR = "color";
|
||||
public static final String STYLE = "style";
|
||||
public static final String ARRAY = "array";
|
||||
public static final String DIMEN = "dimen";
|
||||
public static final String MENU = "menu";
|
||||
public static final String BOOL = "bool";
|
||||
public static final String RAW = "raw";
|
||||
|
||||
//
|
||||
// Class Methods
|
||||
//
|
||||
public enum ResType {
|
||||
ID, BOOL, INTEGER, COLOR, STRING, ARRAY, DRAWABLE, PLURALS,
|
||||
ANIM, ATTR, DIMEN, LAYOUT, MENU, RAW, STYLE, XML,
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out the nuermical ressource id by given {@link ResType}
|
||||
*
|
||||
* @return A valid id if the id could be found, else 0
|
||||
*/
|
||||
public int getResId(ResType resType, final String name) {
|
||||
return _context.getResources().getIdentifier(name, resType.name().toLowerCase(), _context.getPackageName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get String by given string ressource id (nuermic)
|
||||
*/
|
||||
public String rstr(@StringRes int strResId) {
|
||||
return _context.getString(strResId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get String by given string ressource identifier (textual)
|
||||
*/
|
||||
public String rstr(String strResKey) {
|
||||
try {
|
||||
return rstr(getResId(ResType.STRING, strResKey));
|
||||
} catch (Resources.NotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drawable from given ressource identifier
|
||||
*/
|
||||
public Drawable rdrawable(@DrawableRes int resId) {
|
||||
return ContextCompat.getDrawable(_context, resId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color by given color ressource id
|
||||
*/
|
||||
public int rcolor(@ColorRes int resId) {
|
||||
return ContextCompat.getColor(_context, resId);
|
||||
}
|
||||
|
||||
public int getResId(final String type, final String name) {
|
||||
return _context.getResources().getIdentifier(name, type, _context.getPackageName());
|
||||
}
|
||||
|
||||
public boolean areResIdsAvailable(final String type, final String... names) {
|
||||
for (String name : names) {
|
||||
if (getResId(type, name) == 0) {
|
||||
/**
|
||||
* Checks if all given (textual) ressource ids are available
|
||||
*
|
||||
* @param resType A {@link ResType}
|
||||
* @param resIdsTextual A (textual) identifier to be awaited at R.restype.resIdsTextual
|
||||
* @return True if all given ids are available
|
||||
*/
|
||||
public boolean areRessourcesAvailable(final ResType resType, final String... resIdsTextual) {
|
||||
for (String name : resIdsTextual) {
|
||||
if (getResId(resType, name) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//########################
|
||||
//## Methods
|
||||
//########################
|
||||
|
||||
public String colorToHexString(int intColor) {
|
||||
return String.format("#%06X", 0xFFFFFF & intColor);
|
||||
/**
|
||||
* Convert an int color to a hex string. Optionally including alpha value.
|
||||
*
|
||||
* @param intColor The color coded in int
|
||||
* @param withAlpha Optional; Set first bool parameter to true to also include alpha value
|
||||
*/
|
||||
public String colorToHexString(int intColor, boolean... withAlpha) {
|
||||
boolean a = withAlpha != null && withAlpha.length >= 1 && withAlpha[0];
|
||||
return String.format(a ? "#%08X" : "#%06X", (a ? 0xFFFFFFFF : 0xFFFFFF) & intColor);
|
||||
}
|
||||
|
||||
public String getAppVersionName() {
|
||||
|
@ -151,6 +173,10 @@ public class ContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a {@link Intent#ACTION_VIEW} Intent with given paramter
|
||||
* If the parameter is an string a browser will get triggered
|
||||
*/
|
||||
public void openWebpageInExternalBrowser(final String url) {
|
||||
Uri uri = Uri.parse(url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
|
@ -171,13 +197,8 @@ public class ContextUtils {
|
|||
* Falls back to applicationId of the app which may differ from manifest.
|
||||
*/
|
||||
public Object getBuildConfigValue(String fieldName) {
|
||||
String pkg;
|
||||
try {
|
||||
pkg = rstr("manifest_package_id");
|
||||
} catch (Resources.NotFoundException ex) {
|
||||
pkg = _context.getPackageName();
|
||||
}
|
||||
pkg += ".BuildConfig";
|
||||
String pkg = rstr("manifest_package_id");
|
||||
pkg = (pkg != null ? pkg : _context.getPackageName()) + ".BuildConfig";
|
||||
try {
|
||||
Class<?> c = Class.forName(pkg);
|
||||
return c.getField(fieldName).get(null);
|
||||
|
@ -187,7 +208,10 @@ public class ContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean bcbool(String fieldName, boolean defaultValue) {
|
||||
/**
|
||||
* Get a BuildConfig bool value
|
||||
*/
|
||||
public Boolean bcbool(String fieldName, Boolean defaultValue) {
|
||||
Object field = getBuildConfigValue(fieldName);
|
||||
if (field != null && field instanceof Boolean) {
|
||||
return (Boolean) field;
|
||||
|
@ -195,6 +219,9 @@ public class ContextUtils {
|
|||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a BuildConfig string value
|
||||
*/
|
||||
public String bcstr(String fieldName, String defaultValue) {
|
||||
Object field = getBuildConfigValue(fieldName);
|
||||
if (field != null && field instanceof String) {
|
||||
|
@ -203,27 +230,36 @@ public class ContextUtils {
|
|||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a gplay build (requires BuildConfig field)
|
||||
*/
|
||||
public boolean isGooglePlayBuild() {
|
||||
return bcbool("IS_GPLAY_BUILD", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a foss build (requires BuildConfig field)
|
||||
*/
|
||||
public boolean isFossBuild() {
|
||||
return bcbool("IS_FOSS_BUILD", false);
|
||||
}
|
||||
|
||||
// Requires donate__bitcoin_* resources (see below) to be available as string resource
|
||||
public void showDonateBitcoinRequest(@StringRes final int strResBitcoinId, @StringRes final int strResBitcoinAmount, @StringRes final int strResBitcoinMessage, @StringRes final int strResAlternativeDonateUrl) {
|
||||
/**
|
||||
* Request a bitcoin donation with given details.
|
||||
* All parameters are awaited as string resource ids
|
||||
*/
|
||||
public void showDonateBitcoinRequest(@StringRes final int srBitcoinId, @StringRes final int srBitcoinAmount, @StringRes final int srBitcoinMessage, @StringRes final int srAlternativeDonateUrl) {
|
||||
if (!isGooglePlayBuild()) {
|
||||
String btcUri = String.format("bitcoin:%s?amount=%s&label=%s&message=%s",
|
||||
rstr(strResBitcoinId), rstr(strResBitcoinAmount),
|
||||
rstr(strResBitcoinMessage), rstr(strResBitcoinMessage));
|
||||
rstr(srBitcoinId), rstr(srBitcoinAmount),
|
||||
rstr(srBitcoinMessage), rstr(srBitcoinMessage));
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(btcUri));
|
||||
intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
try {
|
||||
_context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
openWebpageInExternalBrowser(rstr(strResAlternativeDonateUrl));
|
||||
openWebpageInExternalBrowser(rstr(srAlternativeDonateUrl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -272,6 +308,9 @@ public class ContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if app with given {@code packageName} is installed
|
||||
*/
|
||||
public boolean isAppInstalled(String packageName) {
|
||||
PackageManager pm = _context.getApplicationContext().getPackageManager();
|
||||
try {
|
||||
|
@ -282,6 +321,9 @@ public class ContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the current app. Supply the class to start on startup
|
||||
*/
|
||||
public void restartApp(Class classToStart) {
|
||||
Intent inte = new Intent(_context, classToStart);
|
||||
PendingIntent inteP = PendingIntent.getActivity(_context, 555, inte, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
@ -295,6 +337,10 @@ public class ContextUtils {
|
|||
Runtime.getRuntime().exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a markdown file from a {@link RawRes}, prepend each line with {@code prepend} text
|
||||
* and convert markdown to html using {@link SimpleMarkdownParser}
|
||||
*/
|
||||
public String loadMarkdownForTextViewFromRaw(@RawRes int rawMdFile, String prepend) {
|
||||
try {
|
||||
return new SimpleMarkdownParser()
|
||||
|
@ -308,52 +354,74 @@ public class ContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load html into a {@link Spanned} object and set the
|
||||
* {@link TextView}'s text using {@link TextView#setText(CharSequence)}
|
||||
*/
|
||||
public void setHtmlToTextView(TextView textView, String html) {
|
||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
textView.setText(new SpannableString(htmlToSpanned(html)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimate this device's screen diagonal size in inches
|
||||
*/
|
||||
public double getEstimatedScreenSizeInches() {
|
||||
DisplayMetrics dm = _context.getResources().getDisplayMetrics();
|
||||
|
||||
double density = dm.density * 160;
|
||||
double x = Math.pow(dm.widthPixels / density, 2);
|
||||
double y = Math.pow(dm.heightPixels / density, 2);
|
||||
double screenInches = Math.sqrt(x + y) * 1.16; // 1.16 = est. Nav/Statusbar
|
||||
screenInches = screenInches < 4.0 ? 4.0 : screenInches;
|
||||
screenInches = screenInches > 12.0 ? 12.0 : screenInches;
|
||||
return screenInches;
|
||||
double calc = dm.density * 160d;
|
||||
double x = Math.pow(dm.widthPixels / calc, 2);
|
||||
double y = Math.pow(dm.heightPixels / calc, 2);
|
||||
calc = Math.sqrt(x + y) * 1.16; // 1.16 = est. Nav/Statusbar
|
||||
return Math.min(12, Math.max(4, calc));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the device is currently in portrait orientation
|
||||
*/
|
||||
public boolean isInPortraitMode() {
|
||||
return _context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
|
||||
}
|
||||
|
||||
public Locale getLocaleByAndroidCode(String code) {
|
||||
if (!TextUtils.isEmpty(code)) {
|
||||
return code.contains("-r")
|
||||
? new Locale(code.substring(0, 2), code.substring(4, 6)) // de-rAt
|
||||
: new Locale(code); // de
|
||||
/**
|
||||
* Get an {@link Locale} out of a android language code
|
||||
* The {@code androidLC} may be in any of the forms: de, en, de-rAt
|
||||
*/
|
||||
public Locale getLocaleByAndroidCode(String androidLC) {
|
||||
if (!TextUtils.isEmpty(androidLC)) {
|
||||
return androidLC.contains("-r")
|
||||
? new Locale(androidLC.substring(0, 2), androidLC.substring(4, 6)) // de-rAt
|
||||
: new Locale(androidLC); // de
|
||||
}
|
||||
return Resources.getSystem().getConfiguration().locale;
|
||||
}
|
||||
|
||||
// en/de/de-rAt ; Empty string -> default locale
|
||||
public void setAppLanguage(String androidLocaleString) {
|
||||
Locale locale = getLocaleByAndroidCode(androidLocaleString);
|
||||
/**
|
||||
* Set the apps language
|
||||
* {@code androidLC} may be in any of the forms: en, de, de-rAt
|
||||
* If given an empty string, the default (system) locale gets loaded
|
||||
*/
|
||||
public void setAppLanguage(String androidLC) {
|
||||
Locale locale = getLocaleByAndroidCode(androidLC);
|
||||
Configuration config = _context.getResources().getConfiguration();
|
||||
config.locale = (locale != null && !androidLocaleString.isEmpty())
|
||||
config.locale = (locale != null && !androidLC.isEmpty())
|
||||
? locale : Resources.getSystem().getConfiguration().locale;
|
||||
_context.getResources().updateConfiguration(config, null);
|
||||
}
|
||||
|
||||
// Find out if color above the given color should be light or dark. true if light
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public boolean shouldColorOnTopBeLight(@ColorInt int colorOnBottomInt) {
|
||||
return 186 > (((0.299 * Color.red(colorOnBottomInt))
|
||||
+ ((0.587 * Color.green(colorOnBottomInt))
|
||||
+ (0.114 * Color.blue(colorOnBottomInt)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a html string to an android {@link Spanned} object
|
||||
*/
|
||||
public Spanned htmlToSpanned(String html) {
|
||||
Spanned result;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
|
@ -364,61 +432,34 @@ public class ContextUtils {
|
|||
return result;
|
||||
}
|
||||
|
||||
public boolean setClipboard(String text) {
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.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;
|
||||
}
|
||||
|
||||
public List<String> getClipboard() {
|
||||
List<String> clipper = new ArrayList<>();
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) {
|
||||
android.text.ClipboardManager cm = ((android.text.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE));
|
||||
if (cm != null) {
|
||||
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; i < data.getItemCount() && i < data.getItemCount(); i++) {
|
||||
clipper.add(data.getItemAt(i).getText().toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return clipper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pixel unit do android dp unit
|
||||
*/
|
||||
public float convertPxToDp(final float px) {
|
||||
return px / _context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert android dp unit to pixel unit
|
||||
*/
|
||||
public float convertDpToPx(final float dp) {
|
||||
return dp * _context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an image into a {@link ImageView} and apply a color filter
|
||||
*/
|
||||
public static void setDrawableWithColorToImageView(ImageView imageView, @DrawableRes int drawableResId, @ColorRes int colorResId) {
|
||||
imageView.setImageResource(drawableResId);
|
||||
imageView.setColorFilter(ContextCompat.getColor(imageView.getContext(), colorResId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link Bitmap} out of a {@link Drawable}
|
||||
*/
|
||||
public Bitmap drawableToBitmap(Drawable drawable) {
|
||||
Bitmap bitmap = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (drawable instanceof VectorDrawable || drawable instanceof VectorDrawableCompat)) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (drawable instanceof VectorDrawable || drawable instanceof VectorDrawableCompat || drawable instanceof AdaptiveIconDrawable)) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
drawable = (DrawableCompat.wrap(drawable)).mutate();
|
||||
}
|
||||
|
@ -434,6 +475,18 @@ public class ContextUtils {
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link Bitmap} out of a {@link DrawableRes}
|
||||
*/
|
||||
public Bitmap drawableToBitmap(@DrawableRes int drawableId) {
|
||||
return drawableToBitmap(ContextCompat.getDrawable(_context, drawableId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link Bitmap} from a given {@code imagePath} on the filesystem
|
||||
* Specifying a {@code maxDimen} is also possible and a value below 2000
|
||||
* is recommended, otherwise a {@link OutOfMemoryError} may occur
|
||||
*/
|
||||
public Bitmap loadImageFromFilesystem(File imagePath, int maxDimen) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
|
@ -462,6 +515,10 @@ public class ContextUtils {
|
|||
return inSampleSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the bitmap so both dimensions are lower or equal to {@code maxDimen}
|
||||
* This keeps the aspect ratio
|
||||
*/
|
||||
public Bitmap scaleBitmap(Bitmap bitmap, int maxDimen) {
|
||||
int picSize = Math.min(bitmap.getHeight(), bitmap.getWidth());
|
||||
float scale = 1.f * maxDimen / picSize;
|
||||
|
@ -470,12 +527,15 @@ public class ContextUtils {
|
|||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given {@link Bitmap} to {@code imageFile}, in {@link CompressFormat#JPEG} format
|
||||
*/
|
||||
public boolean writeImageToFileJpeg(File imageFile, Bitmap image) {
|
||||
return writeImageToFile(imageFile, image, Bitmap.CompressFormat.JPEG, 95);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write bitmap to the filesystem
|
||||
* Write the given {@link Bitmap} to filesystem
|
||||
*
|
||||
* @param targetFile The file to be written in
|
||||
* @param image The image as android {@link Bitmap}
|
||||
|
@ -517,10 +577,14 @@ public class ContextUtils {
|
|||
return false;
|
||||
}
|
||||
|
||||
public Bitmap drawTextOnDrawable(@DrawableRes int resId, String text, int textSize) {
|
||||
/**
|
||||
* Draw text in the center of the given {@link DrawableRes}
|
||||
* This may be useful for e.g. badge counts
|
||||
*/
|
||||
public Bitmap drawTextOnDrawable(@DrawableRes int drawableRes, String text, int textSize) {
|
||||
Resources resources = _context.getResources();
|
||||
float scale = resources.getDisplayMetrics().density;
|
||||
Bitmap bitmap = bitmapToDrawable(resId);
|
||||
Bitmap bitmap = drawableToBitmap(drawableRes);
|
||||
|
||||
bitmap = bitmap.copy(bitmap.getConfig(), true);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
@ -538,24 +602,9 @@ public class ContextUtils {
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
public Bitmap bitmapToDrawable(@DrawableRes int drawableId) {
|
||||
Bitmap bitmap = null;
|
||||
Drawable drawable = ContextCompat.getDrawable(_context, drawableId);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (drawable instanceof VectorDrawable || drawable instanceof VectorDrawableCompat)) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
drawable = (DrawableCompat.wrap(drawable)).mutate();
|
||||
}
|
||||
|
||||
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
} else if (drawable instanceof BitmapDrawable) {
|
||||
bitmap = ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to tint all {@link Menu}s {@link MenuItem}s with given color
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public void tintMenuItems(Menu menu, boolean recurse, @ColorInt int iconColor) {
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
|
@ -567,10 +616,16 @@ public class ContextUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads {@link Drawable} by given {@link DrawableRes} and applies a color
|
||||
*/
|
||||
public Drawable tintDrawable(@DrawableRes int drawableRes, @ColorInt int color) {
|
||||
return tintDrawable(_context.getResources().getDrawable(drawableRes), color);
|
||||
return tintDrawable(rdrawable(drawableRes), color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tint a {@link Drawable} with given {@code color}
|
||||
*/
|
||||
public Drawable tintDrawable(@Nullable Drawable drawable, @ColorInt int color) {
|
||||
if (drawable != null) {
|
||||
drawable = DrawableCompat.wrap(drawable);
|
||||
|
@ -579,6 +634,10 @@ public class ContextUtils {
|
|||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void setSubMenuIconsVisiblity(Menu menu, boolean visible) {
|
||||
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
|
||||
try {
|
||||
|
|
Loading…
Reference in a new issue