package pl.szczodrzynski.edziennik.utils; import android.annotation.SuppressLint; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.CursorLoader; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Matrix; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.provider.MediaStore; import androidx.annotation.AttrRes; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.util.Base64; import android.util.Log; import android.util.TypedValue; import android.webkit.MimeTypeMap; import android.widget.Toast; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.nio.channels.FileChannel; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyStore; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Signature; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.Mac; import javax.crypto.NoSuchPaddingException; import javax.crypto.ShortBufferException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import androidx.core.content.FileProvider; import pl.szczodrzynski.edziennik.App; public class Utils { private static final String TAG = "Utils"; public static String bs(@Nullable String s) { return ns("", s); } public static String bs(String prefix, @Nullable String s) { return ns("", prefix, s); } public static String bs(@Nullable String prefix, @Nullable String s, String suffix) { return ns("", prefix, s, suffix); } public static String ns(String ifNull, @Nullable String s) { return s == null || s.trim().isEmpty() ? ifNull : s; } public static String ns(String ifNull, String prefix, @Nullable String s) { return s == null || s.trim().isEmpty() ? ifNull : prefix+s; } public static String ns(String ifNull, @Nullable String prefix, @Nullable String s, String suffix) { return s == null || s.trim().isEmpty() ? ifNull : (prefix == null ? "" : prefix)+s+suffix; } public static boolean contains(@Nullable List list, @NonNull Object o) { if (list == null) return false; return list.contains(o); /*for (Object o2: list) { if (o.equals(o2)) return true; } return false;*/ } public static List debugLog = new ArrayList<>(); public static void d(String TAG, String message) { if (App.devMode) { Log.d(TAG, message); debugLog.add(TAG+": "+message); } } public static void c(String TAG, String message) { if (App.devMode) { Log.d(TAG, "// " + message); debugLog.add(TAG+": // "+message); } } /** * Returns the first set (high) bit position, from right to left. * @param n the number * @return a 0-indexed position */ public static int rightmostSetBit(int n) { return (int)((Math.log10(n & -n)) / Math.log10(2)); } /** * Returns the last set (high) bit position, from left to right. * @param n the number * @return a 0-indexed position */ public static int leftmostSetBit(int n) { return (int)(Math.log(n) / Math.log(2)); } /** * Returns number of cells needed for given size of the widget. * * @param size Widget size in dp. * @return Size in number of cells. */ public static int getCellsForSize(int size) { int n = 2; while (70 * n - 30 < size) { ++n; } return n - 1; } // EXCEPTION: thread does not change /*public static void exception(String TAG, Response response, @NonNull Throwable throwable, String initialApiResponse, SyncCallback callback, Context activityContext) { //d(TAG, "Thread/exception1/"+Thread.currentThread().getName()); if (Thread.currentThread().getName().equals("main")) { AsyncTask.execute(() -> { exceptionRun(TAG, response, throwable, initialApiResponse, callback, activityContext, true); }); } else { exceptionRun(TAG, response, throwable, initialApiResponse, callback, activityContext, false); } } private static void exceptionRun(String TAG, Response response, @NonNull Throwable throwable, String initialApiResponse, SyncCallback callback, Context activityContext, boolean finishOnMainThread) { //d(TAG, "Thread/exception2/"+Thread.currentThread().getName()); String apiResponse = initialApiResponse; throwable.printStackTrace(); if (response != null) { //d(TAG, response.code() + " " + response.message()); if (apiResponse == null) { apiResponse = response.code()+" "+response.message()+"\n"; if (response.raw().body() != null) { try { apiResponse += response.raw().body().string(); } catch (Exception e) { e.printStackTrace(); apiResponse += "Exception while getting response body:\n"+Log.getStackTraceString(e); } } else { apiResponse += "Response body is null."; } } String apiResponsePrefix = "Request:\n"; apiResponsePrefix += response.request().url().toString()+"\n"; apiResponsePrefix += response.request().headers().toString()+"\n"; apiResponsePrefix += response.request().bodyToString(); apiResponsePrefix += "\n\nResponse:\n"; apiResponse = apiResponsePrefix + apiResponse; } if (callback != null) { String finalApiResponse = apiResponse; if (!finishOnMainThread) { exceptionFinish(TAG, response, throwable, finalApiResponse, callback, activityContext); return; } new Handler(activityContext != null ? activityContext.getMainLooper() : Looper.getMainLooper()).post(() -> { exceptionFinish(TAG, response, throwable, finalApiResponse, callback, activityContext); }); } } private static void exceptionFinish(String TAG, Response response, @NonNull Throwable throwable, String finalApiResponse, SyncCallback callback, Context activityContext) { //d(TAG, "Thread/exception3/"+Thread.currentThread().getName()); if (throwable instanceof UnknownHostException) { callback.onError(activityContext, Error.CODE_NO_INTERNET, "", throwable, finalApiResponse); } else if (throwable instanceof SSLException) { callback.onError(activityContext, Error.CODE_SSL_ERROR, "", throwable, finalApiResponse); } else if (throwable instanceof SocketTimeoutException) { callback.onError(activityContext, Error.CODE_TIMEOUT, "", throwable, finalApiResponse); } else if (throwable instanceof InterruptedIOException) { callback.onError(activityContext, Error.CODE_NO_INTERNET, "", throwable, finalApiResponse); } else { if (response != null) { if (response.code() == 424 || response.code() == 400 || response.code() == 401 || response.code() == 500 || response.code() == 503 || response.code() == 404) { callback.onError(activityContext, CODE_MAINTENANCE, response.code() + " " + response.message() + " " + throwable.getMessage(), throwable, finalApiResponse); } else { callback.onError(activityContext, CODE_OTHER, response.code() + " " + response.message() + " " + throwable.getMessage(), throwable, finalApiResponse); } } else { callback.onError(activityContext, CODE_OTHER, throwable.getMessage(), throwable, finalApiResponse); } } }*/ public static String hexFromColorInt(@ColorInt int color) { return String.format("%06X", (0xFFFFFF & color)); } public static String getRealPathFromURI(Context context, Uri contentUri) { String[] proj = { MediaStore.Images.Media.DATA }; CursorLoader loader = new CursorLoader(context, contentUri, proj, null, null, null); Cursor cursor = loader.loadInBackground(); int column_index; String result = null; try { column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); result = cursor.getString(column_index); cursor.close(); } catch (Exception e) { e.printStackTrace(); } return result; } public static int strToInt(String s, int defaultValue) { try { return Integer.parseInt(s); } catch (Exception e) { e.printStackTrace(); return defaultValue; } } public static int strToInt(String s) { return Integer.parseInt(s); } public static String intToStr(Integer i) { return Integer.toString(i); } public static int crc16(final byte[] buffer) { int crc = 0xFFFF; for (byte aBuffer : buffer) { crc = ((crc >>> 8) | (crc << 8)) & 0xffff; crc ^= (aBuffer & 0xff); // byte to int, trunc sign crc ^= ((crc & 0xff) >> 4); crc ^= (crc << 12) & 0xffff; crc ^= ((crc & 0xFF) << 5) & 0xffff; } crc &= 0xffff; return crc+32768; } public static long crc32(byte[] buffer) { CRC32 crc = new CRC32(); crc.update(buffer); return crc.getValue(); } public static String toPascalCase(String source) { return source.toUpperCase().charAt(0)+source.toLowerCase().substring(1); } @ColorInt public static int getAttr(Context context, @AttrRes int resourceId) { TypedValue typedValue = new TypedValue(); Resources.Theme theme = context.getTheme(); theme.resolveAttribute(resourceId, typedValue, true); return typedValue.data; } public static int dpToPx(int dp) { return (int) (dp * Resources.getSystem().getDisplayMetrics().density); } public static int pxToDp(int px) { return (int) (px / Resources.getSystem().getDisplayMetrics().density); } public static void openGooglePlay(Context context) { openGooglePlay(context, context.getPackageName()); } public static void openGooglePlay(Context context, String packageName) { try { context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } catch (android.content.ActivityNotFoundException e) { context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + packageName)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } } public static void openUrl(Context context, String url) { Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(url)); context.startActivity(i); } public static String checkAppExists(Context context, String packageName) { try { PackageInfo packageInfo; packageInfo = context.getPackageManager().getPackageInfo(packageName, 0); if (packageInfo != null) { Log.d(TAG, packageInfo.toString()); Log.d(TAG, packageInfo.packageName+" "+packageInfo.versionName+" "+packageInfo.versionCode); return packageInfo.versionName; } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } } public static void copy(File src, File dst) throws IOException { FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst); FileChannel inChannel = inStream.getChannel(); FileChannel outChannel = outStream.getChannel(); inChannel.transferTo(0, inChannel.size(), outChannel); inStream.close(); outStream.close(); } public static Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) { int width = bm.getWidth(); int height = bm.getHeight(); float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; // CREATE A MATRIX FOR THE MANIPULATION Matrix matrix = new Matrix(); // RESIZE THE BIT MAP matrix.postScale(scaleWidth, scaleHeight); // "RECREATE" THE NEW BITMAP Bitmap resizedBitmap = Bitmap.createBitmap( bm, 0, 0, width, height, matrix, false); bm.recycle(); return resizedBitmap; } public static class VulcanRequestEncryptionUtils { private static final String ALGORITHM_NAME = "SHA1withRSA"; private static final String CERT_TYPE = "pkcs12"; private static final String CONTAINER_NAME = "LoginCert"; private static final String PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06"; public static String signContent(byte[] contents, final InputStream cert) throws IOException, GeneralSecurityException, NullPointerException { final KeyStore instance = KeyStore.getInstance(CERT_TYPE); instance.load(cert, PASSWORD.toCharArray()); final PrivateKey privateKey = (PrivateKey) instance.getKey(CONTAINER_NAME, PASSWORD.toCharArray()); final Signature instance2 = Signature.getInstance(ALGORITHM_NAME); instance2.initSign(privateKey); instance2.update(contents); return Base64.encodeToString(instance2.sign(), Base64.DEFAULT).replace("\n", ""); } } public static class VulcanQrEncryptionUtils { private static final String PASSWORD = "tDVS4ykCBBAeN33h"; public static String decode(String content) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, ShortBufferException, BadPaddingException, IllegalBlockSizeException { @SuppressLint("GetInstance") Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); byte[] input = Base64.decode(content, Base64.DEFAULT); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(PASSWORD.getBytes(), "AES")); byte[] plainText = new byte[cipher.getOutputSize(input.length)]; int ptLength = cipher.update(input, 0, input.length, plainText, 0); ptLength += cipher.doFinal(plainText, ptLength); return new String(plainText); } } public static class AESCrypt { private static final String ALGORITHM = "AES/CBC/PKCS5Padding"; public static String encrypt(String value, String key) throws Exception { Key keyObj = generateKey(key); Cipher cipher = Cipher.getInstance(AESCrypt.ALGORITHM); byte[] iv = new byte[16]; IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, keyObj, ivSpec); byte [] encryptedByteValue = cipher.doFinal(value.getBytes("utf-8")); String encryptedValue64 = Base64.encodeToString(encryptedByteValue, Base64.DEFAULT); return encryptedValue64; } public static String decrypt(String value, String key) throws Exception { Key keyObj = generateKey(key); Cipher cipher = Cipher.getInstance(AESCrypt.ALGORITHM); byte[] iv = new byte[16]; IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, keyObj, ivSpec); byte[] decryptedValue64 = Base64.decode(value, Base64.DEFAULT); byte [] decryptedByteValue = cipher.doFinal(decryptedValue64); String decryptedValue = new String(decryptedByteValue,"utf-8"); return decryptedValue; } private static Key generateKey(String key) throws Exception { Key keyObj = new SecretKeySpec(key.getBytes(),AESCrypt.ALGORITHM); return keyObj; } } private static String Base64UrlSafe(byte[] data) { String enc = Base64.encodeToString(data, Base64.URL_SAFE | Base64.NO_WRAP); return enc.replace("=", ""); } private final static char[] hexArray = "0123456789abcdef".toCharArray(); public static String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for ( int j = 0; j < bytes.length; j++ ) { int v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } public static String HmacSHA512(String message, String secret) { try { Mac sha_HMAC = Mac.getInstance("HmacSHA512"); SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA512"); sha_HMAC.init(secret_key); return Base64UrlSafe(sha_HMAC.doFinal(message.getBytes())); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return null; } public static String HmacMD5(String message, String secret) { try { Mac sha_HMAC = Mac.getInstance("HmacMD5"); SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacMD5"); sha_HMAC.init(secret_key); return bytesToHex(sha_HMAC.doFinal(message.getBytes())); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return null; } public static String MD5(String message) { try { // Create MD5 Hash MessageDigest md = java.security.MessageDigest.getInstance("MD5"); return Base64UrlSafe(md.digest(message.getBytes())); }catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } public static float getGradeValue(String grade) { switch (grade) { case "1-": return 0.75f; case "1": return 1.00f; case "1+": return 1.50f; case "2-": return 1.75f; case "2": return 2.00f; case "2+": return 2.50f; case "3-": return 2.75f; case "3": return 3.00f; case "3+": return 3.50f; case "4-": return 3.75f; case "4": return 4.00f; case "4+": return 4.50f; case "5-": return 4.75f; case "5": return 5.00f; case "5+": return 5.50f; case "6-": return 5.75f; case "6": return 6.00f; case "6+": return 6.50f; } return 0.00f; } public static int getVulcanGradeColor(String name) { switch (name) { case "1-": case "1": case "1+": return 0xffd65757; case "2-": case "2": case "2+": return 0xff9071b3; case "3-": case "3": case "3+": return 0xffd2ab24; case "4-": case "4": case "4+": return 0xff50b6d6; case "5-": case "5": case "5+": return 0xff2cbd92; case "6-": case "6": case "6+": return 0xff91b43c; default: return 0xff3D5F9C; } } public static int getWordGradeValue(String grade) { switch (grade) { case "niedostateczny": return 1; case "dopuszczający": return 2; case "dostateczny": return 3; case "dobry": return 4; case "bardzo dobry": return 5; case "celujący": return 6; default: return 0; } } public static boolean zipFileAtPath(String sourcePath, String toLocation) { final int BUFFER = 2048; File sourceFile = new File(sourcePath); try { BufferedInputStream origin = null; FileOutputStream dest = new FileOutputStream(toLocation); ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream( dest)); if (sourceFile.isDirectory()) { zipSubFolder(out, sourceFile, sourceFile.getParent().length()); } else { byte data[] = new byte[BUFFER]; FileInputStream fi = new FileInputStream(sourcePath); origin = new BufferedInputStream(fi, BUFFER); ZipEntry entry = new ZipEntry(getLastPathComponent(sourcePath)); entry.setTime(sourceFile.lastModified()); // to keep modification time after unzipping out.putNextEntry(entry); int count; while ((count = origin.read(data, 0, BUFFER)) != -1) { out.write(data, 0, count); } } out.close(); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /* * * Zips a subfolder * */ private static void zipSubFolder(ZipOutputStream out, File folder, int basePathLength) throws IOException { final int BUFFER = 2048; File[] fileList = folder.listFiles(); BufferedInputStream origin = null; for (File file : fileList) { if (file.isDirectory()) { zipSubFolder(out, file, basePathLength); } else { byte data[] = new byte[BUFFER]; String unmodifiedFilePath = file.getPath(); String relativePath = unmodifiedFilePath .substring(basePathLength); FileInputStream fi = new FileInputStream(unmodifiedFilePath); origin = new BufferedInputStream(fi, BUFFER); ZipEntry entry = new ZipEntry(relativePath); entry.setTime(file.lastModified()); // to keep modification time after unzipping out.putNextEntry(entry); int count; while ((count = origin.read(data, 0, BUFFER)) != -1) { out.write(data, 0, count); } origin.close(); } } } /* * gets the last path component * * Example: getLastPathComponent("downloads/example/fileToZip"); * Result: "fileToZip" */ public static String getLastPathComponent(String filePath) { String[] segments = filePath.split("/"); if (segments.length == 0) return ""; String lastPathComponent = segments[segments.length - 1]; return lastPathComponent; } public static String readableFileSize(long size) { if(size <= 0) return "0B"; final String[] units = new String[] { "B", "kB", "MB", "GB", "TB", "PB" }; int digitGroups = (int) (Math.log10(size)/Math.log10(1024)); return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + units[digitGroups]; } public static int monthFromName(String name) { int month = 1; switch (name) { case "stycznia": month = 1; break; case "lutego": month = 2; break; case "marca": month = 3; break; case "kwietnia": month = 4; break; case "maja": month = 5; break; case "czerwca": month = 6; break; case "lipca": month = 7; break; case "sierpnia": month = 8; break; case "września": month = 9; break; case "października": month = 10; break; case "listopada": month = 11; break; case "grudnia": month = 12; break; } return month; } private static String convertStreamToString(InputStream is) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line; boolean first = true; while ((line = reader.readLine()) != null) { if (!(first && !(first = !first))) sb.append("\n"); sb.append(line); } reader.close(); return sb.toString(); } public static String getStringFromFile (File fl) throws Exception { FileInputStream fin = new FileInputStream(fl); String ret = convertStreamToString(fin); //Make sure you close all streams. fin.close(); return ret; } public static void openFile(Context context, File file) { try { Uri uri = Uri.fromFile(file); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file); } String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(getExtensionFromFileName(file.toString())); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri, mimeType == null ? "*/*" : mimeType); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } catch (ActivityNotFoundException e) { Toast.makeText(context, "Nie ma aplikacji która otwiera ten typ pliku", Toast.LENGTH_LONG).show(); } } private static File storageDir = null; public static File getStorageDir() { if (storageDir != null) return storageDir; storageDir = Environment.getExternalStoragePublicDirectory("Szkolny.eu"); storageDir.mkdirs(); return storageDir; } public static void writeStringToFile(File file, String data) throws IOException { OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file)); outputStreamWriter.write(data); outputStreamWriter.close(); } public static String getExtensionFromFileName(String fileName) { return fileName.substring(fileName.lastIndexOf(".")+1).toLowerCase(); } public static String getCurrentTimeUsingCalendar() { Calendar cal = Calendar.getInstance(); Date date=cal.getTime(); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); return dateFormat.format(date); } }