Files
2020-07-18 21:44:27 -04:00

1691 lines
66 KiB
Java

package com.eveningoutpost.dexdrip.Models;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ContextThemeWrapper;
import android.text.InputType;
import android.text.method.DigitsKeyListener;
import android.util.Base64;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.View;
import android.widget.Toast;
import com.activeandroid.ActiveAndroid;
import com.eveningoutpost.dexdrip.Home;
import com.eveningoutpost.dexdrip.R;
import com.eveningoutpost.dexdrip.UtilityModels.Constants;
import com.eveningoutpost.dexdrip.UtilityModels.PersistentStore;
import com.eveningoutpost.dexdrip.UtilityModels.Pref;
import com.eveningoutpost.dexdrip.UtilityModels.XdripNotificationCompat;
import com.eveningoutpost.dexdrip.utils.BestGZIPOutputStream;
import com.eveningoutpost.dexdrip.utils.CipherUtils;
import com.eveningoutpost.dexdrip.xdrip;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInts;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import static android.bluetooth.BluetoothDevice.PAIRING_VARIANT_PIN;
import static android.content.Context.ALARM_SERVICE;
import static com.eveningoutpost.dexdrip.stats.StatsActivity.SHOW_STATISTICS_PRINT_COLOR;
/**
* Created by jamorham on 06/01/16.
* <p>
* lazy helper class for utilities
*/
public class JoH {
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
private final static String TAG = "jamorham JoH";
private final static int PAIRING_VARIANT_PASSKEY = 1; // hidden in api
private final static boolean debug_wakelocks = false;
private static double benchmark_time = 0;
private static Map<String, Double> benchmarks = new HashMap<String, Double>();
private static final Map<String, Long> rateLimits = new HashMap<>();
public static boolean buggy_samsung = false; // flag set when we detect samsung devices which do not perform to android specifications
// quick string conversion with leading zero
public static String qs0(double x, int digits) {
final String qs = qs(x, digits);
return qs.startsWith(".") ? "0" + qs : qs;
}
// qs = quick string conversion of double for printing
public static String qs(double x) {
return qs(x, 2);
}
// singletons to avoid repeated allocation
private static DecimalFormatSymbols dfs;
private static DecimalFormat df;
public static String qs(double x, int digits) {
if (digits == -1) {
digits = 0;
if (((int) x != x)) {
digits++;
if ((((int) x * 10) / 10 != x)) {
digits++;
if ((((int) x * 100) / 100 != x)) digits++;
}
}
}
if (dfs == null) {
final DecimalFormatSymbols local_dfs = new DecimalFormatSymbols();
local_dfs.setDecimalSeparator('.');
dfs = local_dfs; // avoid race condition
}
final DecimalFormat this_df;
// use singleton if on ui thread otherwise allocate new as DecimalFormat is not thread safe
if (Thread.currentThread().getId() == 1) {
if (df == null) {
final DecimalFormat local_df = new DecimalFormat("#", dfs);
local_df.setMinimumIntegerDigits(1);
df = local_df; // avoid race condition
}
this_df = df;
} else {
this_df = new DecimalFormat("#", dfs);
}
this_df.setMaximumFractionDigits(digits);
return this_df.format(x);
}
public static double ts() {
return new Date().getTime();
}
public static long tsl() {
return System.currentTimeMillis();
}
public static long uptime() {
return SystemClock.uptimeMillis();
}
public static boolean upForAtLeastMins(int mins) {
return uptime() > Constants.MINUTE_IN_MS * mins;
}
public static long msSince(long when) {
return (tsl() - when);
}
public static long msTill(long when) {
return (when - tsl());
}
public static long absMsSince(long when) {
return Math.abs(tsl() - when);
}
public static String bytesToHex(byte[] bytes) {
if (bytes == null) return "<empty>";
final char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
final int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static byte[] tolerantHexStringToByteArray(String str) {
return hexStringToByteArray(str.toUpperCase().replaceAll("[^A-F0-9]",""));
}
public static byte[] hexStringToByteArray(String str) {
try {
str = str.toUpperCase().trim();
if (str.length() == 0) return null;
final int len = str.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16));
}
return data;
} catch (Exception e) {
Log.e(TAG, "Exception processing hexString: " + e);
return null;
}
}
public static String macFormat(final String unformatted) {
if (unformatted == null) return null;
return unformatted.replaceAll("[^a-fA-F0-9]","").replaceAll("(.{2})", "$1:").substring(0,17);
}
public static <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> mapSortedByValue(Map<K, V> map, boolean descending) {
final SortedSet<Map.Entry<K, V>> sortedSet = new TreeSet<>((value1, value2) -> {
int result = descending ? value2.getValue().compareTo(value1.getValue())
: value1.getValue().compareTo(value2.getValue());
return result != 0 ? result : 1;
});
sortedSet.addAll(map.entrySet());
return sortedSet;
}
public static String compressString(String source) {
try {
Deflater deflater = new Deflater();
deflater.setInput(source.getBytes(Charset.forName("UTF-8")));
deflater.finish();
byte[] buf = new byte[source.length() + 256];
int count = deflater.deflate(buf);
// check count
deflater.end();
return Base64.encodeToString(buf, 0, count, Base64.NO_WRAP);
} catch (Exception e) {
return null;
}
}
public static byte[] compressStringToBytes(String string) {
try {
ByteArrayOutputStream output = new ByteArrayOutputStream(string.length());
BestGZIPOutputStream gzipped_data = new BestGZIPOutputStream(output);
gzipped_data.write(string.getBytes(Charset.forName("UTF-8")));
gzipped_data.close();
byte[] compressed = output.toByteArray();
output.close();
return compressed;
} catch (Exception e) {
Log.e(TAG, "Exception in compress: " + e.toString());
return new byte[0];
}
}
public static byte[] compressBytesforPayload(byte[] bytes) {
return compressBytesToBytes(Bytes.concat(bytes, bchecksum(bytes)));
}
public static byte[] compressBytesToBytes(byte[] bytes) {
try {
ByteArrayOutputStream output = new ByteArrayOutputStream(bytes.length);
BestGZIPOutputStream gzipped_data = new BestGZIPOutputStream(output);
gzipped_data.write(bytes);
gzipped_data.close();
byte[] compressed = output.toByteArray();
output.close();
return compressed;
} catch (Exception e) {
Log.e(TAG, "Exception in compress: " + e.toString());
return new byte[0];
}
}
public static byte[] decompressBytesToBytes(byte[] bytes) {
try {
Log.d(TAG, "Decompressing bytes size: " + bytes.length);
byte[] buffer = new byte[8192];
int bytes_read;
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
ByteArrayOutputStream output = new ByteArrayOutputStream(bytes.length);
GZIPInputStream gzipped_data = new GZIPInputStream(input, buffer.length);
while ((bytes_read = gzipped_data.read(buffer)) != -1) {
output.write(buffer, 0, bytes_read);
}
gzipped_data.close();
input.close();
// output.close();
return output.toByteArray();
} catch (Exception e) {
Log.e(TAG, "Exception in decompress: " + e.toString());
return new byte[0];
}
}
public static String uncompressString(String input) {
try {
byte[] bytes = Base64.decode(input, Base64.NO_WRAP);
Inflater inflater = new Inflater();
inflater.setInput(bytes);
inflater.finished();
byte[] buf = new byte[10000]; // max packet size because not using stream
int count = inflater.inflate(buf);
inflater.end();
Log.d(TAG, "Inflated bytes: " + count);
return new String(buf, 0, count, "UTF-8");
} catch (Exception e) {
Log.e(TAG, "Got exception uncompressing string");
return null;
}
}
public static String base64encode(String input) {
try {
return new String(Base64.encode(input.getBytes("UTF-8"), Base64.NO_WRAP), "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Got unsupported encoding: " + e);
return "encode-error";
}
}
public static String base64decode(String input) {
try {
return new String(Base64.decode(input.getBytes("UTF-8"), Base64.NO_WRAP), "UTF-8");
} catch (UnsupportedEncodingException | IllegalArgumentException e) {
Log.e(TAG, "Got unsupported encoding: " + e);
return "decode-error";
}
}
public static String base64encodeBytes(byte[] input) {
try {
return new String(Base64.encode(input, Base64.NO_WRAP), "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Got unsupported encoding: " + e);
return "encode-error";
}
}
public static byte[] base64decodeBytes(String input) {
try {
return Base64.decode(input.getBytes("UTF-8"), Base64.NO_WRAP);
} catch (UnsupportedEncodingException | IllegalArgumentException e) {
Log.e(TAG, "Got unsupported encoding: " + e);
return new byte[0];
}
}
public static String ucFirst(String input) {
return input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase();
}
public static boolean isSamsung() {
return Build.MANUFACTURER.toLowerCase().contains("samsung");
}
private static final String BUGGY_SAMSUNG_ENABLED = "buggy-samsung-enabled";
public static void persistentBuggySamsungCheck() {
if (!buggy_samsung) {
if (JoH.isSamsung() && PersistentStore.getLong(BUGGY_SAMSUNG_ENABLED) > 4) {
buggy_samsung = true;
UserError.Log.d(TAG,"Enabling buggy samsung mode due to historical pattern");
}
}
}
public static void setBuggySamsungEnabled() {
if (!buggy_samsung) {
JoH.buggy_samsung = true;
PersistentStore.incrementLong(BUGGY_SAMSUNG_ENABLED);
}
}
public static class DecimalKeyListener extends DigitsKeyListener {
private final char[] acceptedCharacters =
new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
new DecimalFormat().getDecimalFormatSymbols().getDecimalSeparator()};
@Override
protected char[] getAcceptedChars() {
return acceptedCharacters;
}
public int getInputType() {
return InputType.TYPE_CLASS_NUMBER;
}
}
public static String backTrace() {
return backTrace(1);
}
public static String backTrace(int depth) {
try {
StackTraceElement stack = new Exception().getStackTrace()[2 + depth];
StackTraceElement stackb = new Exception().getStackTrace()[3 + depth];
String[] stackclassa = stack.getClassName().split("\\.");
String[] stackbclassa = stackb.getClassName().split("\\.");
return stackbclassa[stackbclassa.length - 1] + "::" + stackb.getMethodName()
+ " -> " + stackclassa[stackclassa.length - 1] + "::" + stack.getMethodName();
} catch (Exception e) {
return "unknown backtrace: " + e.toString();
}
}
public static String backTraceShort(int depth) {
try {
final StackTraceElement stackb = new Exception().getStackTrace()[3 + depth];
return stackb.getMethodName();
} catch (Exception e) {
return "unknown backtrace: " + e.toString();
}
}
public static void benchmark(String name) {
if (name == null) {
if (benchmark_time == 0) {
benchmark_time = ts();
} else {
Log.e(TAG, "Cannot start a benchmark as one is already running - cancelling");
benchmark_time = 0;
}
} else {
if (benchmark_time == 0) {
Log.e(TAG, "Benchmark: " + name + " no benchmark set!");
} else {
Log.i(TAG, "Benchmark: " + name + " " + (ts() - benchmark_time) + " ms");
benchmark_time = 0;
}
}
}
public static void dumpBundle(Bundle bundle, String tag) {
if (bundle != null) {
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
if (value != null) {
UserError.Log.d(tag, String.format("%s %s (%s)", key,
value.toString(), value.getClass().getName()));
}
}
} else {
UserError.Log.d(tag, "Bundle is empty");
}
}
// compare stored byte array hashes
public static synchronized boolean differentBytes(String name, byte[] bytes) {
final String id = "differentBytes-" + name;
final String last_hash = PersistentStore.getString(id);
final String this_hash = CipherUtils.getSHA256(bytes);
if (this_hash.equals(last_hash)) return false;
PersistentStore.setString(id, this_hash);
return true;
}
public static synchronized void clearRatelimit(final String name) {
if (PersistentStore.getLong(name) > 0) {
PersistentStore.setLong(name, 0);
}
if (rateLimits.containsKey(name)) {
rateLimits.remove(name);
}
}
// return true if below rate limit (persistent version)
public static synchronized boolean pratelimit(String name, int seconds) {
// check if over limit
final long time_now = JoH.tsl();
final long rate_time;
if (!rateLimits.containsKey(name)) {
rate_time = PersistentStore.getLong(name); // 0 if undef
} else {
rate_time = rateLimits.get(name);
}
if ((rate_time > 0) && (time_now - rate_time) < (seconds * 1000L)) {
Log.d(TAG, name + " rate limited: " + seconds + " seconds");
return false;
}
// not over limit
rateLimits.put(name, time_now);
PersistentStore.setLong(name, time_now);
return true;
}
// return true if below rate limit
public static synchronized boolean ratelimit(String name, int seconds) {
// check if over limit
if ((rateLimits.containsKey(name)) && (JoH.tsl() - rateLimits.get(name) < (seconds * 1000L))) {
Log.d(TAG, name + " rate limited: " + seconds + " seconds");
return false;
}
// not over limit
rateLimits.put(name, JoH.tsl());
return true;
}
// return true if below rate limit
public static synchronized boolean quietratelimit(String name, int seconds) {
// check if over limit
if ((rateLimits.containsKey(name)) && (JoH.tsl() - rateLimits.get(name) < (seconds * 1000))) {
return false;
}
// not over limit
rateLimits.put(name, JoH.tsl());
return true;
}
// return true if below rate limit
public static synchronized boolean ratelimitmilli(String name, int milliseconds) {
// check if over limit
if ((rateLimits.containsKey(name)) && (JoH.tsl() - rateLimits.get(name) < (milliseconds))) {
Log.d(TAG, name + " rate limited: " + milliseconds + " milliseconds");
return false;
}
// not over limit
rateLimits.put(name, JoH.tsl());
return true;
}
public static String getDeviceDetails() {
final String manufacturer = Build.MANUFACTURER.replace(" ", "_");
final String model = Build.MODEL.replace(" ", "_");
final String version = Integer.toString(Build.VERSION.SDK_INT) + " " + Build.VERSION.RELEASE + " " + Build.VERSION.INCREMENTAL;
return manufacturer + " " + model + " " + version;
}
public static String getVersionDetails() {
try {
return xdrip.getAppContext().getPackageManager().getPackageInfo(xdrip.getAppContext().getPackageName(), PackageManager.GET_META_DATA).versionName;
} catch (Exception e) {
return "Unknown version";
}
}
public static boolean isOldVersion(Context context) {
try {
final Signature[] pinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
if (pinfo.length == 1) {
final Checksum s = new CRC32();
final byte[] ba = pinfo[0].toByteArray();
s.update(ba, 0, ba.length);
if (s.getValue() == 2009579833) return true;
}
} catch (Exception e) {
Log.d(TAG, "exception: " + e);
}
return false;
}
public static boolean getWifiSleepPolicyNever() {
try {
int policy = Settings.Global.getInt(xdrip.getAppContext().getContentResolver(), android.provider.Settings.Global.WIFI_SLEEP_POLICY);
Log.d(TAG, "Current WifiPolicy: " + ((policy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) ? "Never" : Integer.toString(policy)) + " " + Settings.Global.WIFI_SLEEP_POLICY_DEFAULT + " " + Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED);
return (policy == Settings.Global.WIFI_SLEEP_POLICY_NEVER);
} catch (Exception e) {
Log.e(TAG, "Exception during global settings policy");
return true; // we don't know anything
}
}
public static void benchmark_method_start() {
benchmarks.put(backTrace(0), ts());
}
public static void benchmark_method_end() {
String name = backTrace(0);
try {
double timing = ts() - benchmarks.get(name);
Log.i(TAG, "Benchmark: " + name + " " + timing + "ms");
} catch (Exception e) {
Log.e(TAG, "Benchmark: " + name + " no benchmark set!");
}
}
public static void fixActionBar(AppCompatActivity context) {
try {
context.getSupportActionBar().setDisplayShowHomeEnabled(true);
context.getSupportActionBar().setIcon(R.drawable.ic_launcher);
} catch (Exception e) {
Log.e(TAG, "Got exception with supportactionbar: " + e.toString());
}
}
public static HashMap<String, Object> JsonStringtoMap(String json) {
return new Gson().fromJson(json, new TypeToken<HashMap<String, Object>>() {
}.getType());
}
private static Gson gson_instance;
public static Gson defaultGsonInstance() {
if (gson_instance == null) {
gson_instance = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
//.registerTypeAdapter(Date.class, new DateTypeAdapter())
// .serializeSpecialFloatingPointValues()
.create();
}
return gson_instance;
}
public static String hourMinuteString() {
// Date date = new Date();
// SimpleDateFormat sd = new SimpleDateFormat("HH:mm");
// return sd.format(date);
return hourMinuteString(JoH.tsl());
}
public static String hourMinuteString(long timestamp) {
return android.text.format.DateFormat.format("kk:mm", timestamp).toString();
}
public static String dateTimeText(long timestamp) {
return android.text.format.DateFormat.format("yyyy-MM-dd kk:mm:ss", timestamp).toString();
}
public static String dateText(long timestamp) {
return android.text.format.DateFormat.format("yyyy-MM-dd", timestamp).toString();
}
public static long getTimeZoneOffsetMs() {
return new GregorianCalendar().getTimeZone().getRawOffset();
}
public static String niceTimeSince(long t) {
return niceTimeScalar(msSince(t));
}
public static String niceTimeTill(long t) {
return niceTimeScalar(-msSince(t));
}
// temporary
public static String niceTimeScalar(long t) {
String unit = xdrip.getAppContext().getString(R.string.unit_second);
t = t / 1000;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_seconds);
if (t > 59) {
unit = xdrip.getAppContext().getString(R.string.unit_minute);
t = t / 60;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_minutes);
if (t > 59) {
unit = xdrip.getAppContext().getString(R.string.unit_hour);
t = t / 60;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_hours);
if (t > 24) {
unit = xdrip.getAppContext().getString(R.string.unit_day);
t = t / 24;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_days);
if (t > 28) {
unit = xdrip.getAppContext().getString(R.string.unit_week);
t = t / 7;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_weeks);
}
}
}
}
//if (t != 1) unit = unit + "s"; //implemented plurality in every step, because in other languages plurality of time is not every time adding the same character
return qs((double) t, 0) + " " + unit;
}
public static String niceTimeScalar(double t, int digits) {
String unit = xdrip.getAppContext().getString(R.string.unit_second);
t = t / 1000;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_seconds);
if (t > 59) {
unit = xdrip.getAppContext().getString(R.string.unit_minute);
t = t / 60;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_minutes);
if (t > 59) {
unit = xdrip.getAppContext().getString(R.string.unit_hour);
t = t / 60;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_hours);
if (t > 24) {
unit = xdrip.getAppContext().getString(R.string.unit_day);
t = t / 24;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_days);
if (t > 28) {
unit = xdrip.getAppContext().getString(R.string.unit_week);
t = t / 7;
if (t != 1) unit = xdrip.getAppContext().getString(R.string.unit_weeks);
}
}
}
}
//if (t != 1) unit = unit + "s"; //implemented plurality in every step, because in other languages plurality of time is not every time adding the same character
return qs( t, digits) + " " + unit;
}
public static String niceTimeScalarNatural(long t) {
if (t > 3000000) t = t + 10000; // round up by 10 seconds if nearly an hour
if ((t > Constants.DAY_IN_MS) && (t < Constants.WEEK_IN_MS * 2)) {
final SimpleDateFormat df = new SimpleDateFormat("EEEE", Locale.getDefault());
final String day = df.format(new Date(JoH.tsl() + t));
return ((t > Constants.WEEK_IN_MS) ? "next " : "") + day;
} else {
return niceTimeScalar(t);
}
}
public static String niceTimeScalarRedux(long t) {
return niceTimeScalar(t).replaceFirst("^1 ", "");
}
public static String niceTimeScalarShort(long t) {
return niceTimeScalar(t).replaceFirst("([A-z]).*$", "$1");
}
public static String niceTimeScalarShortWithDecimalHours(long t) {
if (t > Constants.HOUR_IN_MS) {
return niceTimeScalar(t,1).replaceFirst("([A-z]).*$", "$1");
} else {
return niceTimeScalar(t).replaceFirst("([A-z]).*$", "$1");
}
}
public static double tolerantParseDouble(String str) throws NumberFormatException {
return Double.parseDouble(str.replace(",", "."));
}
public static double tolerantParseDouble(final String str, final double def) {
if (str == null) return def;
try {
return Double.parseDouble(str.replace(",", "."));
} catch (NumberFormatException e) {
return def;
}
}
public static int tolerantParseInt(final String str, final int def) {
if (str == null) return def;
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return def;
}
}
public static long tolerantParseLong(final String str, final long def) {
if (str == null) return def;
try {
return Long.parseLong(str);
} catch (NumberFormatException e) {
return def;
}
}
public static String getRFC822String(long timestamp) {
final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
return dateFormat.format(new Date(timestamp));
}
public static PowerManager.WakeLock getWakeLock(final String name, int millis) {
final PowerManager pm = (PowerManager) xdrip.getAppContext().getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
wl.acquire(millis);
if (debug_wakelocks) Log.d(TAG, "getWakeLock: " + name + " " + wl.toString());
return wl;
}
public static void releaseWakeLock(PowerManager.WakeLock wl) {
if (debug_wakelocks) Log.d(TAG, "releaseWakeLock: " + wl.toString());
if (wl == null) return;
if (wl.isHeld()) {
try {
wl.release();
} catch (Exception e) {
Log.e(TAG, "Error releasing wakelock: " + e);
}
}
}
public static PowerManager.WakeLock fullWakeLock(final String name, long millis) {
final PowerManager pm = (PowerManager) xdrip.getAppContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, name);
wl.acquire(millis);
if (debug_wakelocks) Log.d(TAG, "fullWakeLock: " + name + " " + wl.toString());
return wl;
}
public static void fullDatabaseReset() {
try {
clearCache();
ActiveAndroid.dispose();
ActiveAndroid.initialize(xdrip.getAppContext());
} catch (Exception e) {
Log.e(TAG,"Error restarting active android db");
}
}
public static void clearCache() {
try {
ActiveAndroid.clearCache();
} catch (Exception e) {
Log.e(TAG, "Error clearing active android cache: " + e);
}
}
public static boolean isLANConnected() {
final ConnectivityManager cm =
(ConnectivityManager) xdrip.getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
final boolean isConnected = activeNetwork != null &&
activeNetwork.isConnected();
return isConnected && ((activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
|| (activeNetwork.getType() == ConnectivityManager.TYPE_ETHERNET)
|| (activeNetwork.getType() == ConnectivityManager.TYPE_BLUETOOTH));
}
public static boolean isMobileDataOrEthernetConnected() {
final ConnectivityManager cm =
(ConnectivityManager) xdrip.getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
final boolean isConnected = activeNetwork != null &&
activeNetwork.isConnected();
return isConnected && ((activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) || (activeNetwork.getType() == ConnectivityManager.TYPE_ETHERNET));
}
public static boolean isAnyNetworkConnected() {
final ConnectivityManager cm =
(ConnectivityManager) xdrip.getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return activeNetwork != null &&
activeNetwork.isConnected();
}
public static boolean isScreenOn() {
final PowerManager pm = (PowerManager) xdrip.getAppContext().getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return pm.isInteractive();
} else {
return pm.isScreenOn();
}
}
public static boolean isOngoingCall() {
try {
AudioManager manager = (AudioManager) xdrip.getAppContext().getSystemService(Context.AUDIO_SERVICE);
return (manager.getMode() == AudioManager.MODE_IN_CALL);
// possibly should have MODE_IN_COMMUNICATION as well
} catch (Exception e) {
return false;
}
}
public static String getWifiSSID() {
try {
final WifiManager wifi_manager = (WifiManager) xdrip.getAppContext().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifi_manager.isWifiEnabled()) {
final WifiInfo wifiInfo = wifi_manager.getConnectionInfo();
if (wifiInfo != null) {
final NetworkInfo.DetailedState wifi_state = WifiInfo.getDetailedStateOf(wifiInfo.getSupplicantState());
if (wifi_state == NetworkInfo.DetailedState.CONNECTED
|| wifi_state == NetworkInfo.DetailedState.OBTAINING_IPADDR
|| wifi_state == NetworkInfo.DetailedState.CAPTIVE_PORTAL_CHECK) {
String ssid = wifiInfo.getSSID();
if (ssid.equals("<unknown ssid>")) return null; // WifiSsid.NONE;
if (ssid.charAt(0) == '"') ssid = ssid.substring(1);
if (ssid.charAt(ssid.length() - 1) == '"')
ssid = ssid.substring(0, ssid.length() - 1);
return ssid;
}
}
}
} catch (Exception e) {
Log.e(TAG, "Got exception in getWifiSSID: " + e);
}
return null;
}
public static boolean getWifiFuzzyMatch(String local, String remote) {
if ((local == null) || (remote == null) || (local.length() == 0) || (remote.length() == 0))
return false;
final int slen = Math.min(local.length(), remote.length());
final int llen = Math.max(local.length(), remote.length());
int matched = 0;
for (int i = 0; i < slen; i++) {
if (local.charAt(i) == (remote.charAt(i))) matched++;
}
boolean result = false;
if (matched == slen) result = true; // shorter string is substring
final double quota = (double) matched / (double) llen;
final int dmatch = llen - matched;
if (slen > 2) {
if (dmatch < 3) result = true;
if (quota > 0.80) result = true;
}
//Log.d(TAG, "l:" + local + " r:" + remote + " slen:" + slen + " llen:" + llen + " matched:" + matched + " q:" + JoH.qs(quota, 2) + " dm:" + dmatch + " RESULT: " + result);
return result;
}
public static boolean runOnUiThread(Runnable theRunnable) {
final Handler mainHandler = new Handler(xdrip.getAppContext().getMainLooper());
return mainHandler.post(theRunnable);
}
public static boolean runOnUiThreadDelayed(Runnable theRunnable, long delay) {
final Handler mainHandler = new Handler(xdrip.getAppContext().getMainLooper());
return mainHandler.postDelayed(theRunnable, delay);
}
public static void removeUiThreadRunnable(Runnable theRunnable) {
final Handler mainHandler = new Handler(xdrip.getAppContext().getMainLooper());
mainHandler.removeCallbacks(theRunnable);
}
public static void hardReset() {
try {
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Exception e) {
// not much to do
}
}
public static void static_toast(final Context context, final String msg, final int length) {
try {
if (!runOnUiThread(new Runnable() {
@Override
public void run() {
try {
Toast.makeText(context, msg, length).show();
Log.i(TAG, "Displaying toast using fallback");
} catch (Exception e) {
Log.e(TAG, "Exception processing runnable toast ui thread: " + e);
Home.toaststatic(msg);
}
}
})) {
Log.e(TAG, "Couldn't display toast via ui thread: " + msg);
Home.toaststatic(msg);
}
} catch (Exception e) {
Log.e(TAG, "Couldn't display toast due to exception: " + msg + " e: " + e.toString());
Home.toaststatic(msg);
}
}
public static void static_toast_long(final String msg) {
static_toast(xdrip.getAppContext(), msg, Toast.LENGTH_LONG);
}
public static void static_toast_short(final String msg) {
static_toast(xdrip.getAppContext(), msg, Toast.LENGTH_SHORT);
}
public static void static_toast_long(Context context, final String msg) {
static_toast(context, msg, Toast.LENGTH_LONG);
}
public static void show_ok_dialog(final Activity activity, final String title, final String message, final Runnable runnable) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.AppTheme));
builder.setTitle(title);
builder.setMessage(message);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
dialog.dismiss();
} catch (Exception e) {
//
}
if (runnable != null) {
runOnUiThreadDelayed(runnable, 10);
}
}
});
builder.create().show();
} catch (Exception e) {
Log.wtf(TAG, "show_dialog exception: " + e);
static_toast_long(message);
}
}
});
}
public static synchronized void playResourceAudio(int id) {
playSoundUri(getResourceURI(id));
}
public static String getResourceURI(int id) {
return ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + xdrip.getAppContext().getPackageName() + "/" + id;
}
public static synchronized MediaPlayer playSoundUri(String soundUri) {
try {
JoH.getWakeLock("joh-playsound", 10000);
final MediaPlayer player = MediaPlayer.create(xdrip.getAppContext(), Uri.parse(soundUri));
player.setLooping(false);
player.start();
return player;
} catch (Exception e) {
Log.wtf(TAG, "Failed to play audio: " + soundUri + " exception:" + e);
return null;
}
}
public static boolean validateMacAddress(final String mac) {
return mac != null && mac.length() == 17 && mac.matches("([\\da-fA-F]{1,2}(?:\\:|$)){6}");
}
public static String urlEncode(String source) {
try {
return URLEncoder.encode(source, "UTF-8");
} catch (Exception e) {
return "encoding-exception";
}
}
public static Object cloneObject(Object obj) {
try {
Object clone = obj.getClass().newInstance();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
field.set(clone, field.get(obj));
}
return clone;
} catch (Exception e) {
return null;
}
}
public static void stopService(Class c) {
xdrip.getAppContext().stopService(new Intent(xdrip.getAppContext(), c));
}
public static void startService(Class c) {
xdrip.getAppContext().startService(new Intent(xdrip.getAppContext(), c));
}
public static void startService(final Class c, final String... args) {
startService(c, null, args);
}
public static void startService(final Class c, final byte[] bytes, final String... args) {
final Intent intent = new Intent(xdrip.getAppContext(), c);
if (bytes != null) {
intent.putExtra("bytes_payload", bytes);
}
if (args.length % 2 == 1) {
throw new RuntimeException("Odd number of args for JoH.startService");
}
for (int i = 0; i < args.length; i += 2) {
intent.putExtra(args[i], args[i + 1]);
}
xdrip.getAppContext().startService(intent);
}
public static void startActivity(Class c) {
xdrip.getAppContext().startActivity(getStartActivityIntent(c));
}
public static Intent getStartActivityIntent(Class c) {
return new Intent(xdrip.getAppContext(), c).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
public static void goFullScreen(boolean fullScreen, View decorView) {
if (fullScreen) {
if (Build.VERSION.SDK_INT >= 19) {
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
} else {
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN);
}
} else {
decorView.setSystemUiVisibility(0); // TODO will this need revisiting in later android vers?
}
}
public static Bitmap screenShot(View view, String annotation) {
if (view == null) {
static_toast_long("View is null in screenshot!");
return null;
}
final int width = view.getWidth();
final int height = view.getHeight();
Log.d(TAG, "Screenshot called: " + width + "," + height);
final Bitmap bitmap = Bitmap.createBitmap(width,
height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
if (Pref.getBooleanDefaultFalse(SHOW_STATISTICS_PRINT_COLOR)) {
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvas.drawRect(0, 0, width, height, paint);
}
view.destroyDrawingCache();
view.layout(0, 0, width, height);
view.draw(canvas);
if (annotation != null) {
final int offset = (annotation != null) ? 40 : 0;
final Bitmap bitmapf = Bitmap.createBitmap(width,
height + offset, Bitmap.Config.ARGB_8888);
final Canvas canvasf = new Canvas(bitmapf);
Paint paint = new Paint();
if (Pref.getBooleanDefaultFalse(SHOW_STATISTICS_PRINT_COLOR)) {
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvasf.drawRect(0, 0, width, offset, paint);
paint.setColor(Color.BLACK);
} else {
paint.setColor(Color.GRAY);
}
paint.setTextSize(20);
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
canvasf.drawBitmap(bitmap, 0, offset, paint);
canvasf.drawText(annotation, 50, (offset / 2) + 5, paint);
bitmap.recycle();
return bitmapf;
}
return bitmap;
}
public static Bitmap screenShot2(View view) {
Log.d(TAG, "Screenshot2 called: " + view.getWidth() + "," + view.getHeight());
view.setDrawingCacheEnabled(true);
view.buildDrawingCache(true);
final Bitmap bitmap = view.getDrawingCache(true);
return bitmap;
}
public static void bitmapToFile(Bitmap bitmap, String path, String fileName) {
if (bitmap == null) return;
Log.d(TAG, "bitmapToFile: " + bitmap.getWidth() + "x" + bitmap.getHeight());
File dir = new File(path);
if (!dir.exists())
dir.mkdirs();
final File file = new File(path, fileName);
try {
FileOutputStream output = new FileOutputStream(file);
final boolean result = bitmap.compress(Bitmap.CompressFormat.PNG, 80, output);
output.flush();
output.close();
Log.d(TAG, "Bitmap compress result: " + result);
} catch (Exception e) {
Log.e(TAG, "Got exception writing bitmap to file: " + e);
}
}
public static void shareImage(Context context, File file) {
Uri uri = Uri.fromFile(file);
final Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("image/*");
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
intent.putExtra(android.content.Intent.EXTRA_TEXT, "");
intent.putExtra(Intent.EXTRA_STREAM, uri);
try {
context.startActivity(Intent.createChooser(intent, "Share"));
} catch (ActivityNotFoundException e) {
static_toast_long("No suitable app to show an image!");
}
}
public static void cancelAlarm(Context context, PendingIntent serviceIntent) {
// do we want a try catch block here?
final AlarmManager alarm = (AlarmManager) context.getSystemService(ALARM_SERVICE);
if (serviceIntent != null) {
Log.d(TAG, "Cancelling alarm " + serviceIntent.getCreatorPackage());
alarm.cancel(serviceIntent);
} else {
Log.d(TAG, "Cancelling alarm: serviceIntent is null");
}
}
public static long wakeUpIntent(Context context, long delayMs, PendingIntent pendingIntent) {
final long wakeTime = JoH.tsl() + delayMs;
if (pendingIntent != null) {
Log.d(TAG, "Scheduling wakeup intent: " + dateTimeText(wakeTime));
final AlarmManager alarm = (AlarmManager) context.getSystemService(ALARM_SERVICE);
try {
alarm.cancel(pendingIntent);
} catch (Exception e) {
Log.e(TAG, "Exception cancelling alarm in wakeUpIntent: " + e);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (buggy_samsung && Pref.getBoolean("allow_samsung_workaround", true)) {
alarm.setAlarmClock(new AlarmManager.AlarmClockInfo(wakeTime, null), pendingIntent);
} else {
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarm.setExact(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent);
} else
alarm.set(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent);
} else {
Log.e(TAG, "wakeUpIntent - pending intent was null!");
}
return wakeTime;
}
public static void scheduleNotification(Context context, String title, String body, int delaySeconds, int notification_id) {
final Intent notificationIntent = new Intent(context, Home.class).putExtra(Home.SHOW_NOTIFICATION, title).putExtra("notification_body", body).putExtra("notification_id", notification_id);
final PendingIntent pendingIntent = PendingIntent.getActivity(context, notification_id, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Log.d(TAG, "Scheduling notification: " + title + " / " + body);
wakeUpIntent(context, delaySeconds * 1000, pendingIntent);
}
public static void cancelNotification(int notificationId) {
try {
final NotificationManager mNotifyMgr = (NotificationManager) xdrip.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotifyMgr.cancel(notificationId);
} catch (Exception e) {
//
}
}
public static void showNotification(String title, String content, PendingIntent intent, int notificationId, boolean sound, boolean vibrate, boolean onetime) {
showNotification(title, content, intent, notificationId, sound, vibrate, null, null);
}
public static void showNotification(String title, String content, PendingIntent intent, int notificationId, boolean sound, boolean vibrate, PendingIntent deleteIntent, Uri sound_uri) {
showNotification(title, content, intent, notificationId, null, sound, vibrate, deleteIntent, sound_uri, null);
}
public static void showNotification(String title, String content, PendingIntent intent, int notificationId, boolean sound, boolean vibrate, PendingIntent deleteIntent, Uri sound_uri, String bigmsg) {
showNotification(title, content, intent, notificationId, null, sound, vibrate, deleteIntent, sound_uri, bigmsg);
}
public static void showNotification(String title, String content, PendingIntent intent, int notificationId, String channelId, boolean sound, boolean vibrate, PendingIntent deleteIntent, Uri sound_uri, String bigmsg) {
final NotificationCompat.Builder mBuilder = notificationBuilder(title, content, intent, channelId);
final long[] vibratePattern = {0, 1000, 300, 1000, 300, 1000};
if (vibrate) mBuilder.setVibrate(vibratePattern);
if (deleteIntent != null) mBuilder.setDeleteIntent(deleteIntent);
mBuilder.setLights(0xff00ff00, 300, 1000);
if (sound) {
Uri soundUri = (sound_uri != null) ? sound_uri : RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mBuilder.setSound(soundUri);
}
if (bigmsg != null) {
mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(bigmsg));
}
final NotificationManager mNotifyMgr = (NotificationManager) xdrip.getAppContext().getSystemService(Context.NOTIFICATION_SERVICE);
// if (!onetime) mNotifyMgr.cancel(notificationId);
mNotifyMgr.notify(notificationId, XdripNotificationCompat.build(mBuilder));
}
private static NotificationCompat.Builder notificationBuilder(String title, String content, PendingIntent intent, String channelId) {
return new NotificationCompat.Builder(xdrip.getAppContext(), channelId)
.setSmallIcon(R.drawable.ic_action_communication_invert_colors_on)
.setContentTitle(title)
.setContentText(content)
.setContentIntent(intent);
}
public static void releaseOrientation(Activity activity) {
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public static void lockOrientation(Activity activity) {
Display display = activity.getWindowManager().getDefaultDisplay();
int rotation = display.getRotation();
int height;
int width;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
height = display.getHeight();
width = display.getWidth();
} else {
Point size = new Point();
display.getSize(size);
height = size.y;
width = size.x;
}
switch (rotation) {
case Surface.ROTATION_90:
if (width > height)
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
else
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
break;
case Surface.ROTATION_180:
if (height > width)
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
else
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
break;
case Surface.ROTATION_270:
if (width > height)
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
else
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
break;
default:
if (height > width)
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
else
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
public static boolean areWeRunningOnAndroidWear() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH
&& (xdrip.getAppContext().getResources().getConfiguration().uiMode
& Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_WATCH;
}
public static boolean isAirplaneModeEnabled(Context context) {
return Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
}
public static byte[] convertPinToBytes(String pin) {
if (pin == null) {
return null;
}
byte[] pinBytes;
try {
pinBytes = pin.getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen
return null;
}
if (pinBytes.length <= 0 || pinBytes.length > 16) {
return null;
}
return pinBytes;
}
public static boolean doPairingRequest(Context context, BroadcastReceiver broadcastReceiver, Intent intent, String mBluetoothDeviceAddress) {
return doPairingRequest(context, broadcastReceiver, intent, mBluetoothDeviceAddress, null);
}
@TargetApi(19)
public static boolean doPairingRequest(Context context, BroadcastReceiver broadcastReceiver, Intent intent, final String mBluetoothDeviceAddress, final String pinHint) {
if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device != null) {
int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
if ((mBluetoothDeviceAddress != null) && (device.getAddress().equals(mBluetoothDeviceAddress))) {
if (type == PAIRING_VARIANT_PASSKEY && pinHint != null) {
return false;
}
if ((type == PAIRING_VARIANT_PIN) && (pinHint != null)) {
device.setPin(convertPinToBytes(pinHint));
Log.d(TAG, "Setting pairing pin to " + pinHint);
broadcastReceiver.abortBroadcast();
}
try {
UserError.Log.e(TAG, "Pairing type: " + type);
if (type != PAIRING_VARIANT_PIN && type != PAIRING_VARIANT_PASSKEY) {
device.setPairingConfirmation(true);
JoH.static_toast_short("xDrip Pairing");
broadcastReceiver.abortBroadcast();
} else {
Log.d(TAG, "Attempting to passthrough PIN pairing");
}
} catch (Exception e) {
UserError.Log.e(TAG, "Could not set pairing confirmation due to exception: " + e);
if (JoH.ratelimit("failed pair confirmation", 200)) {
// BluetoothDevice.PAIRING_VARIANT_CONSENT)
if (type == 3) {
JoH.static_toast_long("Please confirm the bluetooth pairing request");
return false;
} else {
JoH.static_toast_long("Failed to pair, may need to do it via Android Settings");
device.createBond(); // for what it is worth
return false;
}
}
}
} else {
UserError.Log.e(TAG, "Received pairing request for not our device: " + device.getAddress());
}
} else {
UserError.Log.e(TAG, "Device was null in pairing receiver");
}
}
return true;
}
public static String getLocalBluetoothName() {
try {
final String name = BluetoothAdapter.getDefaultAdapter().getName();
if (name == null) return "";
return name;
} catch (Exception e) {
return "";
}
}
public static boolean refreshDeviceCache(String thisTAG, BluetoothGatt gatt){
try {
final Method method = gatt.getClass().getMethod("refresh", new Class[0]);
if (method != null) {
return (Boolean) method.invoke(gatt, new Object[0]);
}
}
catch (Exception e) {
Log.e(thisTAG, "An exception occured while refreshing gatt device cache: "+e);
}
return false;
}
public static boolean createSpecialBond(final String thisTAG, final BluetoothDevice device){
try {
Log.e(thisTAG,"Attempting special bond");
Class[] argTypes = new Class[] { int.class };
final Method method = device.getClass().getMethod("createBond", argTypes);
if (method != null) {
return (Boolean) method.invoke(device, 2);
} else {
Log.e(thisTAG,"CANNOT FIND SPECIAL BOND METHOD!!");
}
}
catch (Exception e) {
Log.e(thisTAG, "An exception occured while creating special bond: "+e);
}
return false;
}
public synchronized static void setBluetoothEnabled(Context context, boolean state) {
try {
if (isAirplaneModeEnabled(context)) {
UserError.Log.e(TAG, "Not setting bluetooth to state: " + state + " due to airplane mode being enabled");
return;
}
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2) {
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
if (bluetoothManager == null) {
UserError.Log.e(TAG, "Couldn't get bluetooth in setBluetoothEnabled");
return;
}
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter(); // local scope only
if (mBluetoothAdapter == null) {
UserError.Log.e(TAG, "Couldn't get bluetooth adapter in setBluetoothEnabled");
return;
}
try {
if (state) {
UserError.Log.i(TAG, "Setting bluetooth enabled");
mBluetoothAdapter.enable();
} else {
UserError.Log.i(TAG, "Setting bluetooth disabled");
mBluetoothAdapter.disable();
}
} catch (Exception e) {
UserError.Log.e(TAG, "Exception when enabling/disabling bluetooth: " + e);
}
} else {
UserError.Log.e(TAG, "Bluetooth low energy not supported");
}
} finally {
//
}
}
public static void niceRestartBluetooth(Context context) {
if (!isOngoingCall()) {
if (ratelimit("joh-restart-bluetooth", 600)) {
restartBluetooth(context);
}
}
}
public synchronized static void restartBluetooth(final Context context) {
restartBluetooth(context, 0);
}
public synchronized static void restartBluetooth(final Context context, final int startInMs) {
new Thread() {
@Override
public void run() {
final PowerManager.WakeLock wl = getWakeLock("restart-bluetooth", 60000);
Log.d(TAG, "Restarting bluetooth");
try {
if (startInMs > 0) {
try {
Thread.sleep(startInMs);
} catch (InterruptedException e) {
Log.d(TAG, "Got interrupted waiting to start resetBluetooth");
}
}
setBluetoothEnabled(context, false);
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
Log.d(TAG, "Got interrupted in resetBluetooth");
}
setBluetoothEnabled(context, true);
} finally {
releaseWakeLock(wl);
}
}
}.start();
}
public static synchronized void unBond(String transmitterMAC) {
UserError.Log.d(TAG, "unBond() start");
if (transmitterMAC == null) return;
try {
final BluetoothAdapter mBluetoothAdapter = ((BluetoothManager) xdrip.getAppContext().getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter();
final Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
if (device.getAddress() != null) {
if (device.getAddress().equals(transmitterMAC)) {
try {
UserError.Log.e(TAG, "removingBond: " + transmitterMAC);
Method m = device.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
} catch (Exception e) {
UserError.Log.e(TAG, e.getMessage(), e);
}
}
}
}
}
} catch (Exception e) {
UserError.Log.e(TAG, "Exception during unbond! " + transmitterMAC, e);
}
UserError.Log.d(TAG, "unBond() finished");
}
public static Map<String, String> bundleToMap(Bundle bundle) {
final HashMap<String, String> map = new HashMap<>();
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
if (value != null) {
map.put(key, value.toString());
}
}
return map;
}
public static void threadSleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
//
}
}
public static ByteBuffer bArrayAsBuffer(byte[] bytes) {
final ByteBuffer bb = ByteBuffer.allocate(bytes.length);
bb.put(bytes);
return bb;
}
public static long checksum(byte[] bytes) {
if (bytes == null) return 0;
final CRC32 crc = new CRC32();
crc.update(bytes);
return crc.getValue();
}
public static byte[] bchecksum(byte[] bytes) {
final long c = checksum(bytes);
final byte[] buf = new byte[4];
ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN).putInt((int) c);
return buf;
}
public static boolean checkChecksum(byte[] bytes) {
if ((bytes == null) || (bytes.length < 4)) return false;
final CRC32 crc = new CRC32();
crc.update(bytes, 0, bytes.length - 4);
final long buffer_crc = UnsignedInts.toLong(ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt(bytes.length - 4));
return buffer_crc == crc.getValue();
}
public static int parseIntWithDefault(String number, int radix, int defaultVal) {
try {
return Integer.parseInt(number, radix);
} catch (NumberFormatException e) {
Log.e(TAG, "Error parsing integer number = " + number + " radix = " + radix);
return defaultVal;
}
}
public static double roundDouble(final double value, int places) {
if (places < 0) throw new IllegalArgumentException("Invalid decimal places");
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
public static float roundFloat(final float value, int places) {
if (places < 0) throw new IllegalArgumentException("Invalid decimal places");
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.floatValue();
}
public static boolean isServiceRunningInForeground(Class<?> serviceClass) {
final ActivityManager manager = (ActivityManager) xdrip.getAppContext().getSystemService(Context.ACTIVITY_SERVICE);
try {
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return service.foreground;
}
}
return false;
} catch (NullPointerException e) {
return false;
}
}
public static boolean emptyString(final String str) {
return str == null || str.length() == 0;
}
}