2014-07-03 00:39:05 +02:00
|
|
|
/*
|
2015-10-29 18:10:07 +01:00
|
|
|
* This is the source code of Telegram for Android v. 3.x.x.
|
2014-07-03 00:39:05 +02:00
|
|
|
* It is licensed under GNU GPL v. 2 or later.
|
|
|
|
* You should have received a copy of the license in this archive (see LICENSE).
|
|
|
|
*
|
2016-01-11 18:19:48 +01:00
|
|
|
* Copyright Nikolai Kudashov, 2013-2016.
|
2014-07-03 00:39:05 +02:00
|
|
|
*/
|
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
package org.telegram.messenger;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
2016-06-24 12:27:15 +02:00
|
|
|
import android.animation.Animator;
|
|
|
|
import android.animation.AnimatorSet;
|
|
|
|
import android.animation.ObjectAnimator;
|
2015-05-21 23:27:27 +02:00
|
|
|
import android.annotation.SuppressLint;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.app.Activity;
|
2014-10-14 22:36:15 +02:00
|
|
|
import android.app.AlertDialog;
|
2015-05-21 23:27:27 +02:00
|
|
|
import android.content.ContentUris;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.content.Context;
|
2014-10-14 22:36:15 +02:00
|
|
|
import android.content.DialogInterface;
|
2015-05-21 23:27:27 +02:00
|
|
|
import android.content.Intent;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.content.pm.ActivityInfo;
|
2015-10-29 18:10:07 +01:00
|
|
|
import android.content.pm.PackageManager;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.content.res.Configuration;
|
2015-05-21 23:27:27 +02:00
|
|
|
import android.database.Cursor;
|
2016-04-22 15:49:00 +02:00
|
|
|
import android.graphics.Bitmap;
|
2016-05-25 23:49:47 +02:00
|
|
|
import android.graphics.BitmapFactory;
|
|
|
|
import android.graphics.BitmapShader;
|
|
|
|
import android.graphics.Canvas;
|
2015-04-09 20:00:14 +02:00
|
|
|
import android.graphics.Color;
|
2016-10-11 13:57:01 +02:00
|
|
|
import android.graphics.Matrix;
|
2016-05-25 23:49:47 +02:00
|
|
|
import android.graphics.Paint;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.graphics.Point;
|
2014-11-06 22:34:47 +01:00
|
|
|
import android.graphics.Rect;
|
2016-05-25 23:49:47 +02:00
|
|
|
import android.graphics.RectF;
|
|
|
|
import android.graphics.Shader;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.graphics.Typeface;
|
2016-04-22 15:49:00 +02:00
|
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
|
|
import android.graphics.drawable.ColorDrawable;
|
2014-11-17 03:44:57 +01:00
|
|
|
import android.graphics.drawable.Drawable;
|
2015-05-21 23:27:27 +02:00
|
|
|
import android.net.Uri;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.os.Build;
|
|
|
|
import android.os.Environment;
|
2015-05-21 23:27:27 +02:00
|
|
|
import android.provider.DocumentsContract;
|
|
|
|
import android.provider.MediaStore;
|
2016-10-11 13:57:01 +02:00
|
|
|
import android.support.v4.content.FileProvider;
|
2014-12-01 18:56:31 +01:00
|
|
|
import android.text.SpannableStringBuilder;
|
|
|
|
import android.text.Spanned;
|
2015-04-09 20:00:14 +02:00
|
|
|
import android.text.style.ForegroundColorSpan;
|
2015-02-26 02:32:51 +01:00
|
|
|
import android.util.DisplayMetrics;
|
2014-11-17 03:44:57 +01:00
|
|
|
import android.util.StateSet;
|
2014-07-03 00:39:05 +02:00
|
|
|
import android.view.Display;
|
|
|
|
import android.view.Surface;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.WindowManager;
|
|
|
|
import android.view.inputmethod.InputMethodManager;
|
2016-06-24 12:27:15 +02:00
|
|
|
import android.webkit.MimeTypeMap;
|
2014-11-11 23:16:17 +01:00
|
|
|
import android.widget.AbsListView;
|
|
|
|
import android.widget.EdgeEffect;
|
2014-10-21 22:35:16 +02:00
|
|
|
import android.widget.EditText;
|
2014-11-11 23:16:17 +01:00
|
|
|
import android.widget.ListView;
|
2015-02-26 02:32:51 +01:00
|
|
|
import android.widget.ProgressBar;
|
2014-10-21 22:35:16 +02:00
|
|
|
import android.widget.TextView;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
import net.hockeyapp.android.CrashManager;
|
|
|
|
import net.hockeyapp.android.CrashManagerListener;
|
|
|
|
import net.hockeyapp.android.UpdateManager;
|
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
import org.telegram.tgnet.ConnectionsManager;
|
|
|
|
import org.telegram.tgnet.TLRPC;
|
2016-04-22 15:49:00 +02:00
|
|
|
import org.telegram.ui.ActionBar.BaseFragment;
|
2015-02-26 02:32:51 +01:00
|
|
|
import org.telegram.ui.Components.ForegroundDetector;
|
2014-12-01 18:56:31 +01:00
|
|
|
import org.telegram.ui.Components.NumberPicker;
|
|
|
|
import org.telegram.ui.Components.TypefaceSpan;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
import java.io.ByteArrayOutputStream;
|
2014-07-03 00:39:05 +02:00
|
|
|
import java.io.File;
|
2015-05-21 23:27:27 +02:00
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
2014-10-21 22:35:16 +02:00
|
|
|
import java.lang.reflect.Field;
|
2014-11-07 11:23:17 +01:00
|
|
|
import java.lang.reflect.Method;
|
2015-05-21 23:27:27 +02:00
|
|
|
import java.text.SimpleDateFormat;
|
2014-12-01 18:56:31 +01:00
|
|
|
import java.util.ArrayList;
|
2015-05-21 23:27:27 +02:00
|
|
|
import java.util.Date;
|
2014-07-03 00:39:05 +02:00
|
|
|
import java.util.Hashtable;
|
2015-05-21 23:27:27 +02:00
|
|
|
import java.util.Locale;
|
2015-11-26 22:04:02 +01:00
|
|
|
import java.util.regex.Pattern;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
|
|
public class AndroidUtilities {
|
2014-10-11 13:30:32 +02:00
|
|
|
|
2015-01-02 23:15:07 +01:00
|
|
|
private static final Hashtable<String, Typeface> typefaceCache = new Hashtable<>();
|
2014-07-03 00:39:05 +02:00
|
|
|
private static int prevOrientation = -10;
|
|
|
|
private static boolean waitingForSms = false;
|
2016-03-16 13:26:32 +01:00
|
|
|
private static boolean waitingForCall = false;
|
2014-10-05 23:23:57 +02:00
|
|
|
private static final Object smsLock = new Object();
|
2016-03-16 13:26:32 +01:00
|
|
|
private static final Object callLock = new Object();
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
|
|
public static int statusBarHeight = 0;
|
|
|
|
public static float density = 1;
|
|
|
|
public static Point displaySize = new Point();
|
2016-10-11 13:57:01 +02:00
|
|
|
public static boolean incorrectDisplaySizeFix;
|
2014-09-30 00:48:11 +02:00
|
|
|
public static Integer photoSize = null;
|
2015-02-26 02:32:51 +01:00
|
|
|
public static DisplayMetrics displayMetrics = new DisplayMetrics();
|
2015-03-26 18:34:47 +01:00
|
|
|
public static int leftBaseline;
|
2015-05-03 13:48:36 +02:00
|
|
|
public static boolean usingHardwareInput;
|
2016-10-11 13:57:01 +02:00
|
|
|
public static boolean isInMultiwindow;
|
2014-09-24 17:08:25 +02:00
|
|
|
private static Boolean isTablet = null;
|
2015-09-24 22:52:02 +02:00
|
|
|
private static int adjustOwnerClassGuid = 0;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
2016-05-25 23:49:47 +02:00
|
|
|
private static Paint roundPaint;
|
|
|
|
private static RectF bitmapRect;
|
|
|
|
|
2015-11-26 22:04:02 +01:00
|
|
|
public static Pattern WEB_URL = null;
|
|
|
|
static {
|
|
|
|
try {
|
|
|
|
final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
|
|
|
|
final Pattern IP_ADDRESS = Pattern.compile(
|
|
|
|
"((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
|
|
|
|
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
|
|
|
|
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
|
|
|
|
+ "|[1-9][0-9]|[0-9]))");
|
|
|
|
final String IRI = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
|
|
|
|
final String GOOD_GTLD_CHAR = "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
|
|
|
|
final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}";
|
|
|
|
final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
|
|
|
|
final Pattern DOMAIN_NAME = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
|
|
|
|
WEB_URL = Pattern.compile(
|
|
|
|
"((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
|
|
|
|
+ "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
|
|
|
|
+ "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
|
|
|
|
+ "(?:" + DOMAIN_NAME + ")"
|
|
|
|
+ "(?:\\:\\d{1,5})?)" // plus option port number
|
|
|
|
+ "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
|
|
|
|
+ "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
|
|
|
|
+ "(?:\\b|$)");
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:39:05 +02:00
|
|
|
static {
|
2015-03-26 18:34:47 +01:00
|
|
|
leftBaseline = isTablet() ? 80 : 72;
|
2016-10-11 13:57:01 +02:00
|
|
|
checkDisplaySize(ApplicationLoader.applicationContext, null);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
|
2016-04-22 15:49:00 +02:00
|
|
|
public static int[] calcDrawableColor(Drawable drawable) {
|
|
|
|
int bitmapColor = 0xff000000;
|
|
|
|
int result[] = new int[2];
|
|
|
|
try {
|
|
|
|
if (drawable instanceof BitmapDrawable) {
|
|
|
|
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
|
|
|
|
if (bitmap != null) {
|
|
|
|
Bitmap b = Bitmaps.createScaledBitmap(bitmap, 1, 1, true);
|
|
|
|
if (b != null) {
|
|
|
|
bitmapColor = b.getPixel(0, 0);
|
|
|
|
b.recycle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (drawable instanceof ColorDrawable) {
|
2016-06-24 12:27:15 +02:00
|
|
|
bitmapColor = ((ColorDrawable) drawable).getColor();
|
2016-04-22 15:49:00 +02:00
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
|
|
|
|
double[] hsv = rgbToHsv((bitmapColor >> 16) & 0xff, (bitmapColor >> 8) & 0xff, bitmapColor & 0xff);
|
|
|
|
hsv[1] = Math.min(1.0, hsv[1] + 0.05 + 0.1 * (1.0 - hsv[1]));
|
|
|
|
hsv[2] = Math.max(0, hsv[2] * 0.65);
|
|
|
|
int rgb[] = hsvToRgb(hsv[0], hsv[1], hsv[2]);
|
|
|
|
result[0] = Color.argb(0x66, rgb[0], rgb[1], rgb[2]);
|
|
|
|
result[1] = Color.argb(0x88, rgb[0], rgb[1], rgb[2]);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static double[] rgbToHsv(int r, int g, int b) {
|
|
|
|
double rf = r / 255.0;
|
|
|
|
double gf = g / 255.0;
|
|
|
|
double bf = b / 255.0;
|
|
|
|
double max = (rf > gf && rf > bf) ? rf : (gf > bf) ? gf : bf;
|
|
|
|
double min = (rf < gf && rf < bf) ? rf : (gf < bf) ? gf : bf;
|
|
|
|
double h, s;
|
|
|
|
double d = max - min;
|
|
|
|
s = max == 0 ? 0 : d / max;
|
|
|
|
if (max == min) {
|
|
|
|
h = 0;
|
|
|
|
} else {
|
|
|
|
if (rf > gf && rf > bf) {
|
|
|
|
h = (gf - bf) / d + (gf < bf ? 6 : 0);
|
|
|
|
} else if (gf > bf) {
|
|
|
|
h = (bf - rf) / d + 2;
|
|
|
|
} else {
|
|
|
|
h = (rf - gf) / d + 4;
|
|
|
|
}
|
|
|
|
h /= 6;
|
|
|
|
}
|
|
|
|
return new double[]{h, s, max};
|
|
|
|
}
|
|
|
|
|
|
|
|
private static int[] hsvToRgb(double h, double s, double v) {
|
|
|
|
double r = 0, g = 0, b = 0;
|
|
|
|
double i = (int) Math.floor(h * 6);
|
|
|
|
double f = h * 6 - i;
|
|
|
|
double p = v * (1 - s);
|
|
|
|
double q = v * (1 - f * s);
|
|
|
|
double t = v * (1 - (1 - f) * s);
|
|
|
|
switch ((int) i % 6) {
|
|
|
|
case 0:
|
|
|
|
r = v;
|
|
|
|
g = t;
|
|
|
|
b = p;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
r = q;
|
|
|
|
g = v;
|
|
|
|
b = p;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
r = p;
|
|
|
|
g = v;
|
|
|
|
b = t;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
r = p;
|
|
|
|
g = q;
|
|
|
|
b = v;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
r = t;
|
|
|
|
g = p;
|
|
|
|
b = v;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
r = v;
|
|
|
|
g = p;
|
|
|
|
b = q;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return new int[]{(int) (r * 255), (int) (g * 255), (int) (b * 255)};
|
|
|
|
}
|
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
public static void requestAdjustResize(Activity activity, int classGuid) {
|
|
|
|
if (activity == null || isTablet()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
|
|
|
adjustOwnerClassGuid = classGuid;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void removeAdjustResize(Activity activity, int classGuid) {
|
|
|
|
if (activity == null || isTablet()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (adjustOwnerClassGuid == classGuid) {
|
|
|
|
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-22 15:49:00 +02:00
|
|
|
public static boolean isGoogleMapsInstalled(final BaseFragment fragment) {
|
|
|
|
try {
|
|
|
|
ApplicationLoader.applicationContext.getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0);
|
|
|
|
return true;
|
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
|
|
if (fragment.getParentActivity() == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity());
|
|
|
|
builder.setMessage("Install Google Maps?");
|
|
|
|
builder.setCancelable(true);
|
|
|
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialogInterface, int i) {
|
|
|
|
try {
|
|
|
|
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.apps.maps"));
|
|
|
|
fragment.getParentActivity().startActivityForResult(intent, 500);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
|
|
|
fragment.showDialog(builder.create());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 23:49:47 +02:00
|
|
|
public static boolean isInternalUri(Uri uri) {
|
|
|
|
String pathString = uri.getPath();
|
|
|
|
if (pathString == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
while (true) {
|
|
|
|
String newPath = Utilities.readlink(pathString);
|
|
|
|
if (newPath == null || newPath.equals(pathString)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pathString = newPath;
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
if (pathString != null) {
|
|
|
|
try {
|
|
|
|
String path = new File(pathString).getCanonicalPath();
|
|
|
|
if (path != null) {
|
|
|
|
pathString = path;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
pathString.replace("/./", "/");
|
|
|
|
//igonre
|
|
|
|
}
|
|
|
|
}
|
2016-05-25 23:49:47 +02:00
|
|
|
return pathString != null && pathString.toLowerCase().contains("/data/data/" + ApplicationLoader.applicationContext.getPackageName() + "/files");
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:39:05 +02:00
|
|
|
public static void lockOrientation(Activity activity) {
|
2016-04-22 15:49:00 +02:00
|
|
|
if (activity == null || prevOrientation != -10) {
|
2014-07-03 00:39:05 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
prevOrientation = activity.getRequestedOrientation();
|
|
|
|
WindowManager manager = (WindowManager)activity.getSystemService(Activity.WINDOW_SERVICE);
|
|
|
|
if (manager != null && manager.getDefaultDisplay() != null) {
|
|
|
|
int rotation = manager.getDefaultDisplay().getRotation();
|
|
|
|
int orientation = activity.getResources().getConfiguration().orientation;
|
|
|
|
|
|
|
|
if (rotation == Surface.ROTATION_270) {
|
|
|
|
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
|
|
} else {
|
2016-04-22 15:49:00 +02:00
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
} else if (rotation == Surface.ROTATION_90) {
|
|
|
|
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
2016-04-22 15:49:00 +02:00
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
2014-07-03 00:39:05 +02:00
|
|
|
} else {
|
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
|
|
}
|
|
|
|
} else if (rotation == Surface.ROTATION_0) {
|
|
|
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
|
|
} else {
|
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
2016-04-22 15:49:00 +02:00
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
2014-07-03 00:39:05 +02:00
|
|
|
} else {
|
2016-04-22 15:49:00 +02:00
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void unlockOrientation(Activity activity) {
|
2016-04-22 15:49:00 +02:00
|
|
|
if (activity == null) {
|
2014-09-24 04:17:27 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
try {
|
|
|
|
if (prevOrientation != -10) {
|
|
|
|
activity.setRequestedOrientation(prevOrientation);
|
|
|
|
prevOrientation = -10;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Typeface getTypeface(String assetPath) {
|
|
|
|
synchronized (typefaceCache) {
|
|
|
|
if (!typefaceCache.containsKey(assetPath)) {
|
|
|
|
try {
|
|
|
|
Typeface t = Typeface.createFromAsset(ApplicationLoader.applicationContext.getAssets(), assetPath);
|
|
|
|
typefaceCache.put(assetPath, t);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("Typefaces", "Could not get typeface '" + assetPath + "' because " + e.getMessage());
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return typefaceCache.get(assetPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isWaitingForSms() {
|
2015-05-21 23:27:27 +02:00
|
|
|
boolean value;
|
2014-07-03 00:39:05 +02:00
|
|
|
synchronized (smsLock) {
|
|
|
|
value = waitingForSms;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setWaitingForSms(boolean value) {
|
|
|
|
synchronized (smsLock) {
|
|
|
|
waitingForSms = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-16 13:26:32 +01:00
|
|
|
public static boolean isWaitingForCall() {
|
|
|
|
boolean value;
|
|
|
|
synchronized (callLock) {
|
|
|
|
value = waitingForCall;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setWaitingForCall(boolean value) {
|
|
|
|
synchronized (callLock) {
|
|
|
|
waitingForCall = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-03 00:39:05 +02:00
|
|
|
public static void showKeyboard(View view) {
|
|
|
|
if (view == null) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-25 23:49:47 +02:00
|
|
|
try {
|
|
|
|
InputMethodManager inputManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isKeyboardShowed(View view) {
|
|
|
|
if (view == null) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-25 23:49:47 +02:00
|
|
|
try {
|
|
|
|
InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
return inputManager.isActive(view);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
return false;
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void hideKeyboard(View view) {
|
|
|
|
if (view == null) {
|
|
|
|
return;
|
|
|
|
}
|
2016-05-25 23:49:47 +02:00
|
|
|
try {
|
|
|
|
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
if (!imm.isActive()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static File getCacheDir() {
|
2015-01-02 23:15:07 +01:00
|
|
|
String state = null;
|
|
|
|
try {
|
|
|
|
state = Environment.getExternalStorageState();
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
if (state == null || state.startsWith(Environment.MEDIA_MOUNTED)) {
|
2014-07-20 01:31:49 +02:00
|
|
|
try {
|
|
|
|
File file = ApplicationLoader.applicationContext.getExternalCacheDir();
|
|
|
|
if (file != null) {
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-20 01:31:49 +02:00
|
|
|
try {
|
|
|
|
File file = ApplicationLoader.applicationContext.getCacheDir();
|
|
|
|
if (file != null) {
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
return new File("");
|
|
|
|
}
|
|
|
|
|
2014-11-06 22:34:47 +01:00
|
|
|
public static int dp(float value) {
|
2015-05-03 13:48:36 +02:00
|
|
|
if (value == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-10-29 18:10:07 +01:00
|
|
|
return (int) Math.ceil(density * value);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
|
2015-05-03 13:48:36 +02:00
|
|
|
public static int compare(int lhs, int rhs) {
|
|
|
|
if (lhs == rhs) {
|
|
|
|
return 0;
|
|
|
|
} else if (lhs > rhs) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-14 22:36:15 +02:00
|
|
|
public static float dpf2(float value) {
|
2015-05-03 13:48:36 +02:00
|
|
|
if (value == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2014-10-14 22:36:15 +02:00
|
|
|
return density * value;
|
|
|
|
}
|
|
|
|
|
2016-10-11 13:57:01 +02:00
|
|
|
public static void checkDisplaySize(Context context, Configuration newConfiguration) {
|
2014-07-03 00:39:05 +02:00
|
|
|
try {
|
2016-10-11 13:57:01 +02:00
|
|
|
density = context.getResources().getDisplayMetrics().density;
|
|
|
|
Configuration configuration = newConfiguration;
|
|
|
|
if (configuration == null) {
|
|
|
|
configuration = context.getResources().getConfiguration();
|
|
|
|
}
|
2015-05-03 13:48:36 +02:00
|
|
|
usingHardwareInput = configuration.keyboard != Configuration.KEYBOARD_NOKEYS && configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
|
2016-10-11 13:57:01 +02:00
|
|
|
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
2014-07-03 00:39:05 +02:00
|
|
|
if (manager != null) {
|
|
|
|
Display display = manager.getDefaultDisplay();
|
|
|
|
if (display != null) {
|
2015-02-26 02:32:51 +01:00
|
|
|
display.getMetrics(displayMetrics);
|
2016-06-24 12:27:15 +02:00
|
|
|
display.getSize(displaySize);
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
if (configuration.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
|
|
|
|
int newSize = (int) Math.ceil(configuration.screenWidthDp * density);
|
|
|
|
if (Math.abs(displaySize.x - newSize) > 3) {
|
|
|
|
displaySize.x = newSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (configuration.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
|
|
|
|
int newSize = (int) Math.ceil(configuration.screenHeightDp * density);
|
|
|
|
if (Math.abs(displaySize.y - newSize) > 3) {
|
|
|
|
displaySize.y = newSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FileLog.e("tmessages", "display size = " + displaySize.x + " " + displaySize.y + " " + displayMetrics.xdpi + "x" + displayMetrics.ydpi);
|
2014-07-03 00:39:05 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
2014-07-27 12:53:00 +02:00
|
|
|
|
2015-02-26 02:32:51 +01:00
|
|
|
public static float getPixelsInCM(float cm, boolean isX) {
|
|
|
|
return (cm / 2.54f) * (isX ? displayMetrics.xdpi : displayMetrics.ydpi);
|
|
|
|
}
|
|
|
|
|
2014-07-27 12:53:00 +02:00
|
|
|
public static long makeBroadcastId(int id) {
|
|
|
|
return 0x0000000100000000L | ((long)id & 0x00000000FFFFFFFFL);
|
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
|
2014-10-14 10:13:16 +02:00
|
|
|
public static int getMyLayerVersion(int layer) {
|
|
|
|
return layer & 0xffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static int getPeerLayerVersion(int layer) {
|
|
|
|
return (layer >> 16) & 0xffff;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static int setMyLayerVersion(int layer, int version) {
|
|
|
|
return layer & 0xffff0000 | version;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static int setPeerLayerVersion(int layer, int version) {
|
|
|
|
return layer & 0x0000ffff | (version << 16);
|
|
|
|
}
|
|
|
|
|
2014-11-06 22:34:47 +01:00
|
|
|
public static void runOnUIThread(Runnable runnable) {
|
|
|
|
runOnUIThread(runnable, 0);
|
2014-10-01 21:55:24 +02:00
|
|
|
}
|
|
|
|
|
2014-11-06 22:34:47 +01:00
|
|
|
public static void runOnUIThread(Runnable runnable, long delay) {
|
2014-10-01 21:55:24 +02:00
|
|
|
if (delay == 0) {
|
|
|
|
ApplicationLoader.applicationHandler.post(runnable);
|
|
|
|
} else {
|
|
|
|
ApplicationLoader.applicationHandler.postDelayed(runnable, delay);
|
|
|
|
}
|
2014-08-22 16:24:33 +02:00
|
|
|
}
|
2014-09-24 04:17:27 +02:00
|
|
|
|
2014-11-06 22:34:47 +01:00
|
|
|
public static void cancelRunOnUIThread(Runnable runnable) {
|
2014-10-09 17:55:05 +02:00
|
|
|
ApplicationLoader.applicationHandler.removeCallbacks(runnable);
|
|
|
|
}
|
|
|
|
|
2014-09-24 04:17:27 +02:00
|
|
|
public static boolean isTablet() {
|
2014-09-24 17:08:25 +02:00
|
|
|
if (isTablet == null) {
|
|
|
|
isTablet = ApplicationLoader.applicationContext.getResources().getBoolean(R.bool.isTablet);
|
|
|
|
}
|
|
|
|
return isTablet;
|
2014-09-24 04:17:27 +02:00
|
|
|
}
|
|
|
|
|
2014-09-25 05:54:35 +02:00
|
|
|
public static boolean isSmallTablet() {
|
2014-09-30 00:48:11 +02:00
|
|
|
float minSide = Math.min(displaySize.x, displaySize.y) / density;
|
|
|
|
return minSide <= 700;
|
2014-09-25 05:54:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static int getMinTabletSide() {
|
|
|
|
if (!isSmallTablet()) {
|
|
|
|
int smallSide = Math.min(displaySize.x, displaySize.y);
|
|
|
|
int leftSide = smallSide * 35 / 100;
|
|
|
|
if (leftSide < dp(320)) {
|
|
|
|
leftSide = dp(320);
|
|
|
|
}
|
|
|
|
return smallSide - leftSide;
|
|
|
|
} else {
|
|
|
|
int smallSide = Math.min(displaySize.x, displaySize.y);
|
|
|
|
int maxSide = Math.max(displaySize.x, displaySize.y);
|
|
|
|
int leftSide = maxSide * 35 / 100;
|
|
|
|
if (leftSide < dp(320)) {
|
|
|
|
leftSide = dp(320);
|
|
|
|
}
|
|
|
|
return Math.min(smallSide, maxSide - leftSide);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-30 00:48:11 +02:00
|
|
|
public static int getPhotoSize() {
|
|
|
|
if (photoSize == null) {
|
|
|
|
if (Build.VERSION.SDK_INT >= 16) {
|
|
|
|
photoSize = 1280;
|
|
|
|
} else {
|
|
|
|
photoSize = 800;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return photoSize;
|
|
|
|
}
|
2014-10-14 22:36:15 +02:00
|
|
|
|
|
|
|
public static String formatTTLString(int ttl) {
|
|
|
|
if (ttl < 60) {
|
|
|
|
return LocaleController.formatPluralString("Seconds", ttl);
|
|
|
|
} else if (ttl < 60 * 60) {
|
|
|
|
return LocaleController.formatPluralString("Minutes", ttl / 60);
|
|
|
|
} else if (ttl < 60 * 60 * 24) {
|
|
|
|
return LocaleController.formatPluralString("Hours", ttl / 60 / 60);
|
|
|
|
} else if (ttl < 60 * 60 * 24 * 7) {
|
|
|
|
return LocaleController.formatPluralString("Days", ttl / 60 / 60 / 24);
|
|
|
|
} else {
|
|
|
|
int days = ttl / 60 / 60 / 24;
|
|
|
|
if (ttl % 7 == 0) {
|
|
|
|
return LocaleController.formatPluralString("Weeks", days / 7);
|
|
|
|
} else {
|
|
|
|
return String.format("%s %s", LocaleController.formatPluralString("Weeks", days / 7), LocaleController.formatPluralString("Days", days % 7));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-21 22:35:16 +02:00
|
|
|
public static AlertDialog.Builder buildTTLAlert(final Context context, final TLRPC.EncryptedChat encryptedChat) {
|
2014-10-14 22:36:15 +02:00
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
|
|
|
builder.setTitle(LocaleController.getString("MessageLifetime", R.string.MessageLifetime));
|
|
|
|
final NumberPicker numberPicker = new NumberPicker(context);
|
|
|
|
numberPicker.setMinValue(0);
|
|
|
|
numberPicker.setMaxValue(20);
|
2014-10-22 22:01:07 +02:00
|
|
|
if (encryptedChat.ttl > 0 && encryptedChat.ttl < 16) {
|
2014-10-14 22:36:15 +02:00
|
|
|
numberPicker.setValue(encryptedChat.ttl);
|
|
|
|
} else if (encryptedChat.ttl == 30) {
|
|
|
|
numberPicker.setValue(16);
|
|
|
|
} else if (encryptedChat.ttl == 60) {
|
|
|
|
numberPicker.setValue(17);
|
|
|
|
} else if (encryptedChat.ttl == 60 * 60) {
|
|
|
|
numberPicker.setValue(18);
|
|
|
|
} else if (encryptedChat.ttl == 60 * 60 * 24) {
|
|
|
|
numberPicker.setValue(19);
|
|
|
|
} else if (encryptedChat.ttl == 60 * 60 * 24 * 7) {
|
|
|
|
numberPicker.setValue(20);
|
2014-10-22 22:01:07 +02:00
|
|
|
} else if (encryptedChat.ttl == 0) {
|
2014-11-21 20:36:21 +01:00
|
|
|
numberPicker.setValue(0);
|
2014-10-14 22:36:15 +02:00
|
|
|
}
|
|
|
|
numberPicker.setFormatter(new NumberPicker.Formatter() {
|
|
|
|
@Override
|
|
|
|
public String format(int value) {
|
|
|
|
if (value == 0) {
|
|
|
|
return LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever);
|
|
|
|
} else if (value >= 1 && value < 16) {
|
|
|
|
return AndroidUtilities.formatTTLString(value);
|
|
|
|
} else if (value == 16) {
|
|
|
|
return AndroidUtilities.formatTTLString(30);
|
|
|
|
} else if (value == 17) {
|
|
|
|
return AndroidUtilities.formatTTLString(60);
|
|
|
|
} else if (value == 18) {
|
|
|
|
return AndroidUtilities.formatTTLString(60 * 60);
|
|
|
|
} else if (value == 19) {
|
|
|
|
return AndroidUtilities.formatTTLString(60 * 60 * 24);
|
|
|
|
} else if (value == 20) {
|
|
|
|
return AndroidUtilities.formatTTLString(60 * 60 * 24 * 7);
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
});
|
|
|
|
builder.setView(numberPicker);
|
|
|
|
builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
int oldValue = encryptedChat.ttl;
|
|
|
|
which = numberPicker.getValue();
|
|
|
|
if (which >= 0 && which < 16) {
|
|
|
|
encryptedChat.ttl = which;
|
|
|
|
} else if (which == 16) {
|
|
|
|
encryptedChat.ttl = 30;
|
|
|
|
} else if (which == 17) {
|
|
|
|
encryptedChat.ttl = 60;
|
|
|
|
} else if (which == 18) {
|
|
|
|
encryptedChat.ttl = 60 * 60;
|
|
|
|
} else if (which == 19) {
|
|
|
|
encryptedChat.ttl = 60 * 60 * 24;
|
|
|
|
} else if (which == 20) {
|
|
|
|
encryptedChat.ttl = 60 * 60 * 24 * 7;
|
|
|
|
}
|
|
|
|
if (oldValue != encryptedChat.ttl) {
|
2014-12-01 18:56:31 +01:00
|
|
|
SecretChatHelper.getInstance().sendTTLMessage(encryptedChat, null);
|
2014-10-14 22:36:15 +02:00
|
|
|
MessagesStorage.getInstance().updateEncryptedChatTTL(encryptedChat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return builder;
|
|
|
|
}
|
2014-10-21 22:35:16 +02:00
|
|
|
|
|
|
|
public static void clearCursorDrawable(EditText editText) {
|
2016-06-24 12:27:15 +02:00
|
|
|
if (editText == null) {
|
2014-10-21 22:35:16 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes");
|
|
|
|
mCursorDrawableRes.setAccessible(true);
|
|
|
|
mCursorDrawableRes.setInt(editText, 0);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
2014-11-06 22:34:47 +01:00
|
|
|
|
2015-02-26 02:32:51 +01:00
|
|
|
public static void setProgressBarAnimationDuration(ProgressBar progressBar, int duration) {
|
|
|
|
if (progressBar == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
Field mCursorDrawableRes = ProgressBar.class.getDeclaredField("mDuration");
|
|
|
|
mCursorDrawableRes.setAccessible(true);
|
|
|
|
mCursorDrawableRes.setInt(progressBar, duration);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 23:49:47 +02:00
|
|
|
private static Intent createShortcutIntent(long did, boolean forDelete) {
|
|
|
|
Intent shortcutIntent = new Intent(ApplicationLoader.applicationContext, OpenChatReceiver.class);
|
|
|
|
|
|
|
|
int lower_id = (int) did;
|
|
|
|
int high_id = (int) (did >> 32);
|
|
|
|
|
|
|
|
TLRPC.User user = null;
|
|
|
|
TLRPC.Chat chat = null;
|
|
|
|
if (lower_id == 0) {
|
|
|
|
shortcutIntent.putExtra("encId", high_id);
|
|
|
|
TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id);
|
|
|
|
if (encryptedChat == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
user = MessagesController.getInstance().getUser(encryptedChat.user_id);
|
|
|
|
} else if (lower_id > 0) {
|
|
|
|
shortcutIntent.putExtra("userId", lower_id);
|
|
|
|
user = MessagesController.getInstance().getUser(lower_id);
|
|
|
|
} else if (lower_id < 0) {
|
|
|
|
chat = MessagesController.getInstance().getChat(-lower_id);
|
|
|
|
shortcutIntent.putExtra("chatId", -lower_id);
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (user == null && chat == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
String name;
|
|
|
|
TLRPC.FileLocation photo = null;
|
|
|
|
|
|
|
|
if (user != null) {
|
|
|
|
name = ContactsController.formatName(user.first_name, user.last_name);
|
|
|
|
if (user.photo != null) {
|
|
|
|
photo = user.photo.photo_small;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
name = chat.title;
|
|
|
|
if (chat.photo != null) {
|
|
|
|
photo = chat.photo.photo_small;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
shortcutIntent.setAction("com.tmessages.openchat" + did);
|
|
|
|
shortcutIntent.addFlags(0x4000000);
|
|
|
|
|
|
|
|
Intent addIntent = new Intent();
|
|
|
|
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
|
|
|
|
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
|
|
|
|
addIntent.putExtra("duplicate", false);
|
|
|
|
if (!forDelete) {
|
|
|
|
Bitmap bitmap = null;
|
|
|
|
if (photo != null) {
|
|
|
|
try {
|
|
|
|
File path = FileLoader.getPathToAttach(photo, true);
|
|
|
|
bitmap = BitmapFactory.decodeFile(path.toString());
|
|
|
|
if (bitmap != null) {
|
|
|
|
int size = AndroidUtilities.dp(58);
|
|
|
|
Bitmap result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
|
|
|
result.eraseColor(Color.TRANSPARENT);
|
|
|
|
Canvas canvas = new Canvas(result);
|
|
|
|
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
|
|
|
if (roundPaint == null) {
|
|
|
|
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
|
|
bitmapRect = new RectF();
|
|
|
|
}
|
|
|
|
float scale = size / (float) bitmap.getWidth();
|
|
|
|
canvas.save();
|
|
|
|
canvas.scale(scale, scale);
|
|
|
|
roundPaint.setShader(shader);
|
|
|
|
bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
|
|
|
|
canvas.drawRoundRect(bitmapRect, bitmap.getWidth(), bitmap.getHeight(), roundPaint);
|
|
|
|
canvas.restore();
|
|
|
|
Drawable drawable = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.book_logo);
|
|
|
|
int w = AndroidUtilities.dp(15);
|
|
|
|
int left = size - w - AndroidUtilities.dp(2);
|
|
|
|
int top = size - w - AndroidUtilities.dp(2);
|
|
|
|
drawable.setBounds(left, top, left + w, top + w);
|
|
|
|
drawable.draw(canvas);
|
|
|
|
try {
|
|
|
|
canvas.setBitmap(null);
|
|
|
|
} catch (Exception e) {
|
|
|
|
//don't promt, this will crash on 2.x
|
|
|
|
}
|
|
|
|
bitmap = result;
|
|
|
|
}
|
|
|
|
} catch (Throwable e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bitmap != null) {
|
|
|
|
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
|
|
|
|
} else {
|
|
|
|
if (user != null) {
|
|
|
|
if (user.bot) {
|
|
|
|
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(ApplicationLoader.applicationContext, R.drawable.book_bot));
|
|
|
|
} else {
|
|
|
|
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(ApplicationLoader.applicationContext, R.drawable.book_user));
|
|
|
|
}
|
|
|
|
} else if (chat != null) {
|
|
|
|
if (ChatObject.isChannel(chat) && !chat.megagroup) {
|
|
|
|
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(ApplicationLoader.applicationContext, R.drawable.book_channel));
|
|
|
|
} else {
|
|
|
|
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(ApplicationLoader.applicationContext, R.drawable.book_group));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return addIntent;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void installShortcut(long did) {
|
|
|
|
try {
|
|
|
|
Intent addIntent = createShortcutIntent(did, false);
|
|
|
|
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
|
|
|
|
ApplicationLoader.applicationContext.sendBroadcast(addIntent);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void uninstallShortcut(long did) {
|
|
|
|
try {
|
|
|
|
Intent addIntent = createShortcutIntent(did, true);
|
|
|
|
addIntent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
|
|
|
|
ApplicationLoader.applicationContext.sendBroadcast(addIntent);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-11 13:57:01 +02:00
|
|
|
private static Field mAttachInfoField;
|
|
|
|
private static Field mStableInsetsField;
|
2014-11-06 22:34:47 +01:00
|
|
|
public static int getViewInset(View view) {
|
2015-12-09 19:27:52 +01:00
|
|
|
if (view == null || Build.VERSION.SDK_INT < 21 || view.getHeight() == AndroidUtilities.displaySize.y || view.getHeight() == AndroidUtilities.displaySize.y - statusBarHeight) {
|
2014-11-06 22:34:47 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
try {
|
2016-10-11 13:57:01 +02:00
|
|
|
if (mAttachInfoField == null) {
|
|
|
|
mAttachInfoField = View.class.getDeclaredField("mAttachInfo");
|
|
|
|
mAttachInfoField.setAccessible(true);
|
|
|
|
}
|
2014-11-06 22:34:47 +01:00
|
|
|
Object mAttachInfo = mAttachInfoField.get(view);
|
|
|
|
if (mAttachInfo != null) {
|
2016-10-11 13:57:01 +02:00
|
|
|
if (mStableInsetsField == null) {
|
|
|
|
mStableInsetsField = mAttachInfo.getClass().getDeclaredField("mStableInsets");
|
|
|
|
mStableInsetsField.setAccessible(true);
|
|
|
|
}
|
|
|
|
Rect insets = (Rect) mStableInsetsField.get(mAttachInfo);
|
2014-11-06 22:34:47 +01:00
|
|
|
return insets.bottom;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-07 11:23:17 +01:00
|
|
|
public static Point getRealScreenSize() {
|
|
|
|
Point size = new Point();
|
|
|
|
try {
|
|
|
|
WindowManager windowManager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE);
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
|
|
|
windowManager.getDefaultDisplay().getRealSize(size);
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
Method mGetRawW = Display.class.getMethod("getRawWidth");
|
|
|
|
Method mGetRawH = Display.class.getMethod("getRawHeight");
|
|
|
|
size.set((Integer) mGetRawW.invoke(windowManager.getDefaultDisplay()), (Integer) mGetRawH.invoke(windowManager.getDefaultDisplay()));
|
|
|
|
} catch (Exception e) {
|
2014-11-07 21:10:12 +01:00
|
|
|
size.set(windowManager.getDefaultDisplay().getWidth(), windowManager.getDefaultDisplay().getHeight());
|
2014-11-07 11:23:17 +01:00
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
2014-11-11 23:16:17 +01:00
|
|
|
|
2016-06-24 12:27:15 +02:00
|
|
|
public static CharSequence getTrimmedString(CharSequence src) {
|
|
|
|
if (src == null || src.length() == 0) {
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
while (src.length() > 0 && (src.charAt(0) == '\n' || src.charAt(0) == ' ')) {
|
|
|
|
src = src.subSequence(1, src.length());
|
|
|
|
}
|
|
|
|
while (src.length() > 0 && (src.charAt(src.length() - 1) == '\n' || src.charAt(src.length() - 1) == ' ')) {
|
|
|
|
src = src.subSequence(0, src.length() - 1);
|
|
|
|
}
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
2014-11-17 23:04:31 +01:00
|
|
|
public static void setListViewEdgeEffectColor(AbsListView listView, int color) {
|
2014-11-11 23:16:17 +01:00
|
|
|
if (Build.VERSION.SDK_INT >= 21) {
|
|
|
|
try {
|
|
|
|
Field field = AbsListView.class.getDeclaredField("mEdgeGlowTop");
|
|
|
|
field.setAccessible(true);
|
|
|
|
EdgeEffect mEdgeGlowTop = (EdgeEffect) field.get(listView);
|
|
|
|
if (mEdgeGlowTop != null) {
|
|
|
|
mEdgeGlowTop.setColor(color);
|
|
|
|
}
|
|
|
|
|
|
|
|
field = AbsListView.class.getDeclaredField("mEdgeGlowBottom");
|
|
|
|
field.setAccessible(true);
|
|
|
|
EdgeEffect mEdgeGlowBottom = (EdgeEffect) field.get(listView);
|
|
|
|
if (mEdgeGlowBottom != null) {
|
|
|
|
mEdgeGlowBottom.setColor(color);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-17 03:44:57 +01:00
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
@SuppressLint("NewApi")
|
2014-11-17 03:44:57 +01:00
|
|
|
public static void clearDrawableAnimation(View view) {
|
|
|
|
if (Build.VERSION.SDK_INT < 21 || view == null) {
|
|
|
|
return;
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
Drawable drawable;
|
2014-11-17 03:44:57 +01:00
|
|
|
if (view instanceof ListView) {
|
|
|
|
drawable = ((ListView) view).getSelector();
|
|
|
|
if (drawable != null) {
|
|
|
|
drawable.setState(StateSet.NOTHING);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
drawable = view.getBackground();
|
|
|
|
if (drawable != null) {
|
|
|
|
drawable.setState(StateSet.NOTHING);
|
|
|
|
drawable.jumpToCurrentState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-01 18:56:31 +01:00
|
|
|
|
2015-06-29 19:12:11 +02:00
|
|
|
public static final int FLAG_TAG_BR = 1;
|
|
|
|
public static final int FLAG_TAG_BOLD = 2;
|
|
|
|
public static final int FLAG_TAG_COLOR = 4;
|
|
|
|
public static final int FLAG_TAG_ALL = FLAG_TAG_BR | FLAG_TAG_BOLD | FLAG_TAG_COLOR;
|
|
|
|
|
2016-04-22 15:49:00 +02:00
|
|
|
public static SpannableStringBuilder replaceTags(String str) {
|
2015-06-29 19:12:11 +02:00
|
|
|
return replaceTags(str, FLAG_TAG_ALL);
|
|
|
|
}
|
|
|
|
|
2016-04-22 15:49:00 +02:00
|
|
|
public static SpannableStringBuilder replaceTags(String str, int flag) {
|
2015-04-09 20:00:14 +02:00
|
|
|
try {
|
2015-05-21 23:27:27 +02:00
|
|
|
int start;
|
|
|
|
int end;
|
2015-04-09 20:00:14 +02:00
|
|
|
StringBuilder stringBuilder = new StringBuilder(str);
|
2015-06-29 19:12:11 +02:00
|
|
|
if ((flag & FLAG_TAG_BR) != 0) {
|
|
|
|
while ((start = stringBuilder.indexOf("<br>")) != -1) {
|
|
|
|
stringBuilder.replace(start, start + 4, "\n");
|
|
|
|
}
|
|
|
|
while ((start = stringBuilder.indexOf("<br/>")) != -1) {
|
|
|
|
stringBuilder.replace(start, start + 5, "\n");
|
|
|
|
}
|
2015-04-09 20:00:14 +02:00
|
|
|
}
|
|
|
|
ArrayList<Integer> bolds = new ArrayList<>();
|
2015-06-29 19:12:11 +02:00
|
|
|
if ((flag & FLAG_TAG_BOLD) != 0) {
|
|
|
|
while ((start = stringBuilder.indexOf("<b>")) != -1) {
|
2015-04-09 20:00:14 +02:00
|
|
|
stringBuilder.replace(start, start + 3, "");
|
|
|
|
end = stringBuilder.indexOf("</b>");
|
2015-05-03 13:48:36 +02:00
|
|
|
if (end == -1) {
|
|
|
|
end = stringBuilder.indexOf("<b>");
|
|
|
|
}
|
2015-04-09 20:00:14 +02:00
|
|
|
stringBuilder.replace(end, end + 4, "");
|
|
|
|
bolds.add(start);
|
|
|
|
bolds.add(end);
|
2015-06-29 19:12:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ArrayList<Integer> colors = new ArrayList<>();
|
|
|
|
if ((flag & FLAG_TAG_COLOR) != 0) {
|
|
|
|
while ((start = stringBuilder.indexOf("<c#")) != -1) {
|
|
|
|
stringBuilder.replace(start, start + 2, "");
|
|
|
|
end = stringBuilder.indexOf(">", start);
|
|
|
|
int color = Color.parseColor(stringBuilder.substring(start, end));
|
|
|
|
stringBuilder.replace(start, end + 1, "");
|
2015-04-09 20:00:14 +02:00
|
|
|
end = stringBuilder.indexOf("</c>");
|
|
|
|
stringBuilder.replace(end, end + 4, "");
|
2015-06-29 19:12:11 +02:00
|
|
|
colors.add(start);
|
2015-04-09 20:00:14 +02:00
|
|
|
colors.add(end);
|
|
|
|
colors.add(color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(stringBuilder);
|
|
|
|
for (int a = 0; a < bolds.size() / 2; a++) {
|
|
|
|
spannableStringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), bolds.get(a * 2), bolds.get(a * 2 + 1), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
}
|
|
|
|
for (int a = 0; a < colors.size() / 3; a++) {
|
|
|
|
spannableStringBuilder.setSpan(new ForegroundColorSpan(colors.get(a * 3 + 2)), colors.get(a * 3), colors.get(a * 3 + 1), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
}
|
|
|
|
return spannableStringBuilder;
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
2014-12-01 18:56:31 +01:00
|
|
|
}
|
2015-04-09 20:00:14 +02:00
|
|
|
return new SpannableStringBuilder(str);
|
2014-12-01 18:56:31 +01:00
|
|
|
}
|
2015-02-26 02:32:51 +01:00
|
|
|
|
|
|
|
public static boolean needShowPasscode(boolean reset) {
|
2016-06-24 12:27:15 +02:00
|
|
|
boolean wasInBackground = ForegroundDetector.getInstance().isWasInBackground(reset);
|
|
|
|
if (reset) {
|
|
|
|
ForegroundDetector.getInstance().resetBackgroundVar();
|
2015-02-26 02:32:51 +01:00
|
|
|
}
|
|
|
|
return UserConfig.passcodeHash.length() > 0 && wasInBackground &&
|
|
|
|
(UserConfig.appLocked || UserConfig.autoLockIn != 0 && UserConfig.lastPauseTime != 0 && !UserConfig.appLocked && (UserConfig.lastPauseTime + UserConfig.autoLockIn) <= ConnectionsManager.getInstance().getCurrentTime());
|
|
|
|
}
|
2015-02-27 20:57:58 +01:00
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
public static void shakeView(final View view, final float x, final int num) {
|
2015-04-09 20:00:14 +02:00
|
|
|
if (num == 6) {
|
2016-06-24 12:27:15 +02:00
|
|
|
view.setTranslationX(0);
|
2015-04-09 20:00:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-06-24 12:27:15 +02:00
|
|
|
AnimatorSet animatorSet = new AnimatorSet();
|
|
|
|
animatorSet.playTogether(ObjectAnimator.ofFloat(view, "translationX", AndroidUtilities.dp(x)));
|
|
|
|
animatorSet.setDuration(50);
|
|
|
|
animatorSet.addListener(new AnimatorListenerAdapterProxy() {
|
2015-04-09 20:00:14 +02:00
|
|
|
@Override
|
2016-06-24 12:27:15 +02:00
|
|
|
public void onAnimationEnd(Animator animation) {
|
2015-09-24 22:52:02 +02:00
|
|
|
shakeView(view, num == 5 ? 0 : -x, num + 1);
|
2015-04-09 20:00:14 +02:00
|
|
|
}
|
|
|
|
});
|
2016-06-24 12:27:15 +02:00
|
|
|
animatorSet.start();
|
2015-04-09 20:00:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*public static String ellipsize(String text, int maxLines, int maxWidth, TextPaint paint) {
|
|
|
|
if (text == null || paint == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
int count;
|
|
|
|
int offset = 0;
|
|
|
|
StringBuilder result = null;
|
|
|
|
TextView
|
|
|
|
for (int a = 0; a < maxLines; a++) {
|
|
|
|
count = paint.breakText(text, true, maxWidth, null);
|
|
|
|
if (a != maxLines - 1) {
|
|
|
|
if (result == null) {
|
|
|
|
result = new StringBuilder(count * maxLines + 1);
|
|
|
|
}
|
|
|
|
boolean foundSpace = false;
|
|
|
|
for (int c = count - 1; c >= offset; c--) {
|
|
|
|
if (text.charAt(c) == ' ') {
|
|
|
|
foundSpace = true;
|
|
|
|
result.append(text.substring(offset, c - 1));
|
|
|
|
offset = c - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!foundSpace) {
|
|
|
|
offset = count;
|
|
|
|
}
|
|
|
|
text = text.substring(0, offset);
|
|
|
|
} else if (maxLines == 1) {
|
|
|
|
return text.substring(0, count);
|
|
|
|
} else {
|
|
|
|
result.append(text.substring(0, count));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result.toString();
|
|
|
|
}*/
|
|
|
|
|
2015-02-27 20:57:58 +01:00
|
|
|
/*public static void turnOffHardwareAcceleration(Window window) {
|
2016-06-24 12:27:15 +02:00
|
|
|
if (window == null || Build.MODEL == null) {
|
2015-02-27 20:57:58 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Build.MODEL.contains("GT-S5301") ||
|
|
|
|
Build.MODEL.contains("GT-S5303") ||
|
|
|
|
Build.MODEL.contains("GT-B5330") ||
|
|
|
|
Build.MODEL.contains("GT-S5302") ||
|
|
|
|
Build.MODEL.contains("GT-S6012B") ||
|
|
|
|
Build.MODEL.contains("MegaFon_SP-AI")) {
|
|
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
|
|
|
|
}
|
|
|
|
}*/
|
2015-05-21 23:27:27 +02:00
|
|
|
|
|
|
|
public static void checkForCrashes(Activity context) {
|
2015-11-26 22:04:02 +01:00
|
|
|
CrashManager.register(context, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH, new CrashManagerListener() {
|
2015-05-21 23:27:27 +02:00
|
|
|
@Override
|
|
|
|
public boolean includeDeviceData() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void checkForUpdates(Activity context) {
|
|
|
|
if (BuildVars.DEBUG_VERSION) {
|
2015-11-26 22:04:02 +01:00
|
|
|
UpdateManager.register(context, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH);
|
2015-05-21 23:27:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void unregisterUpdates() {
|
|
|
|
if (BuildVars.DEBUG_VERSION) {
|
|
|
|
UpdateManager.unregister();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 23:49:47 +02:00
|
|
|
public static void addToClipboard(CharSequence str) {
|
|
|
|
try {
|
2016-06-24 12:27:15 +02:00
|
|
|
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
|
|
|
android.content.ClipData clip = android.content.ClipData.newPlainText("label", str);
|
|
|
|
clipboard.setPrimaryClip(clip);
|
2016-05-25 23:49:47 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
public static void addMediaToGallery(String fromPath) {
|
|
|
|
if (fromPath == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
File f = new File(fromPath);
|
|
|
|
Uri contentUri = Uri.fromFile(f);
|
|
|
|
addMediaToGallery(contentUri);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void addMediaToGallery(Uri uri) {
|
|
|
|
if (uri == null) {
|
|
|
|
return;
|
|
|
|
}
|
2015-10-29 18:10:07 +01:00
|
|
|
try {
|
|
|
|
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
|
|
|
mediaScanIntent.setData(uri);
|
|
|
|
ApplicationLoader.applicationContext.sendBroadcast(mediaScanIntent);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private static File getAlbumDir() {
|
2015-10-29 18:10:07 +01:00
|
|
|
if (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
|
|
return FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE);
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
File storageDir = null;
|
|
|
|
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
|
|
|
storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Telegram");
|
|
|
|
if (!storageDir.mkdirs()) {
|
|
|
|
if (!storageDir.exists()){
|
|
|
|
FileLog.d("tmessages", "failed to create directory");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FileLog.d("tmessages", "External storage is not mounted READ/WRITE.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return storageDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressLint("NewApi")
|
|
|
|
public static String getPath(final Uri uri) {
|
|
|
|
try {
|
|
|
|
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
|
|
|
if (isKitKat && DocumentsContract.isDocumentUri(ApplicationLoader.applicationContext, uri)) {
|
|
|
|
if (isExternalStorageDocument(uri)) {
|
|
|
|
final String docId = DocumentsContract.getDocumentId(uri);
|
|
|
|
final String[] split = docId.split(":");
|
|
|
|
final String type = split[0];
|
|
|
|
if ("primary".equalsIgnoreCase(type)) {
|
|
|
|
return Environment.getExternalStorageDirectory() + "/" + split[1];
|
|
|
|
}
|
|
|
|
} else if (isDownloadsDocument(uri)) {
|
|
|
|
final String id = DocumentsContract.getDocumentId(uri);
|
|
|
|
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
|
|
|
|
return getDataColumn(ApplicationLoader.applicationContext, contentUri, null, null);
|
|
|
|
} else if (isMediaDocument(uri)) {
|
|
|
|
final String docId = DocumentsContract.getDocumentId(uri);
|
|
|
|
final String[] split = docId.split(":");
|
|
|
|
final String type = split[0];
|
|
|
|
|
|
|
|
Uri contentUri = null;
|
|
|
|
switch (type) {
|
|
|
|
case "image":
|
|
|
|
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
|
|
|
break;
|
|
|
|
case "video":
|
|
|
|
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
|
|
|
break;
|
|
|
|
case "audio":
|
|
|
|
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
final String selection = "_id=?";
|
|
|
|
final String[] selectionArgs = new String[] {
|
|
|
|
split[1]
|
|
|
|
};
|
|
|
|
|
|
|
|
return getDataColumn(ApplicationLoader.applicationContext, contentUri, selection, selectionArgs);
|
|
|
|
}
|
|
|
|
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
|
|
|
return getDataColumn(ApplicationLoader.applicationContext, uri, null, null);
|
|
|
|
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
|
|
|
return uri.getPath();
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
|
|
|
|
|
|
|
|
Cursor cursor = null;
|
|
|
|
final String column = "_data";
|
|
|
|
final String[] projection = {
|
|
|
|
column
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
|
|
|
if (cursor != null && cursor.moveToFirst()) {
|
|
|
|
final int column_index = cursor.getColumnIndexOrThrow(column);
|
2016-03-16 13:26:32 +01:00
|
|
|
String value = cursor.getString(column_index);
|
|
|
|
if (value.startsWith("content://") || !value.startsWith("/") && !value.startsWith("file://")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return value;
|
2015-05-21 23:27:27 +02:00
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
} finally {
|
|
|
|
if (cursor != null) {
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isExternalStorageDocument(Uri uri) {
|
|
|
|
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isDownloadsDocument(Uri uri) {
|
|
|
|
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isMediaDocument(Uri uri) {
|
|
|
|
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static File generatePicturePath() {
|
|
|
|
try {
|
|
|
|
File storageDir = getAlbumDir();
|
|
|
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
|
|
|
|
return new File(storageDir, "IMG_" + timeStamp + ".jpg");
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static CharSequence generateSearchName(String name, String name2, String q) {
|
|
|
|
if (name == null && name2 == null) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
SpannableStringBuilder builder = new SpannableStringBuilder();
|
|
|
|
String wholeString = name;
|
|
|
|
if (wholeString == null || wholeString.length() == 0) {
|
|
|
|
wholeString = name2;
|
|
|
|
} else if (name2 != null && name2.length() != 0) {
|
|
|
|
wholeString += " " + name2;
|
|
|
|
}
|
|
|
|
wholeString = wholeString.trim();
|
|
|
|
String lower = " " + wholeString.toLowerCase();
|
|
|
|
|
|
|
|
int index;
|
|
|
|
int lastIndex = 0;
|
|
|
|
while ((index = lower.indexOf(" " + q, lastIndex)) != -1) {
|
|
|
|
int idx = index - (index == 0 ? 0 : 1);
|
|
|
|
int end = q.length() + (index == 0 ? 0 : 1) + idx;
|
|
|
|
|
|
|
|
if (lastIndex != 0 && lastIndex != idx + 1) {
|
|
|
|
builder.append(wholeString.substring(lastIndex, idx));
|
|
|
|
} else if (lastIndex == 0 && idx != 0) {
|
|
|
|
builder.append(wholeString.substring(0, idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
String query = wholeString.substring(idx, end);
|
|
|
|
if (query.startsWith(" ")) {
|
|
|
|
builder.append(" ");
|
|
|
|
}
|
|
|
|
query = query.trim();
|
|
|
|
builder.append(AndroidUtilities.replaceTags("<c#ff4d83b3>" + query + "</c>"));
|
|
|
|
|
|
|
|
lastIndex = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lastIndex != -1 && lastIndex != wholeString.length()) {
|
|
|
|
builder.append(wholeString.substring(lastIndex, wholeString.length()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static File generateVideoPath() {
|
|
|
|
try {
|
|
|
|
File storageDir = getAlbumDir();
|
|
|
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
|
|
|
|
return new File(storageDir, "VID_" + timeStamp + ".mp4");
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String formatFileSize(long size) {
|
|
|
|
if (size < 1024) {
|
|
|
|
return String.format("%d B", size);
|
|
|
|
} else if (size < 1024 * 1024) {
|
|
|
|
return String.format("%.1f KB", size / 1024.0f);
|
|
|
|
} else if (size < 1024 * 1024 * 1024) {
|
|
|
|
return String.format("%.1f MB", size / 1024.0f / 1024.0f);
|
|
|
|
} else {
|
|
|
|
return String.format("%.1f GB", size / 1024.0f / 1024.0f / 1024.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static byte[] decodeQuotedPrintable(final byte[] bytes) {
|
|
|
|
if (bytes == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
|
|
for (int i = 0; i < bytes.length; i++) {
|
|
|
|
final int b = bytes[i];
|
|
|
|
if (b == '=') {
|
|
|
|
try {
|
|
|
|
final int u = Character.digit((char) bytes[++i], 16);
|
|
|
|
final int l = Character.digit((char) bytes[++i], 16);
|
|
|
|
buffer.write((char) ((u << 4) + l));
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
buffer.write(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
byte[] array = buffer.toByteArray();
|
|
|
|
try {
|
|
|
|
buffer.close();
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean copyFile(InputStream sourceFile, File destFile) throws IOException {
|
|
|
|
OutputStream out = new FileOutputStream(destFile);
|
|
|
|
byte[] buf = new byte[4096];
|
|
|
|
int len;
|
|
|
|
while ((len = sourceFile.read(buf)) > 0) {
|
|
|
|
Thread.yield();
|
|
|
|
out.write(buf, 0, len);
|
|
|
|
}
|
|
|
|
out.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean copyFile(File sourceFile, File destFile) throws IOException {
|
|
|
|
if (!destFile.exists()) {
|
|
|
|
destFile.createNewFile();
|
|
|
|
}
|
|
|
|
FileInputStream source = null;
|
|
|
|
FileOutputStream destination = null;
|
|
|
|
try {
|
|
|
|
source = new FileInputStream(sourceFile);
|
|
|
|
destination = new FileOutputStream(destFile);
|
|
|
|
destination.getChannel().transferFrom(source.getChannel(), 0, source.getChannel().size());
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
return false;
|
|
|
|
} finally {
|
|
|
|
if (source != null) {
|
|
|
|
source.close();
|
|
|
|
}
|
|
|
|
if (destination != null) {
|
|
|
|
destination.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2016-03-06 02:49:31 +01:00
|
|
|
|
|
|
|
public static byte[] calcAuthKeyHash(byte[] auth_key) {
|
|
|
|
byte[] sha1 = Utilities.computeSHA1(auth_key);
|
|
|
|
byte[] key_hash = new byte[16];
|
|
|
|
System.arraycopy(sha1, 0, key_hash, 0, 16);
|
|
|
|
return key_hash;
|
|
|
|
}
|
2016-06-24 12:27:15 +02:00
|
|
|
|
|
|
|
public static void openForView(MessageObject message, Activity activity) throws Exception {
|
|
|
|
File f = null;
|
|
|
|
String fileName = message.getFileName();
|
|
|
|
if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) {
|
|
|
|
f = new File(message.messageOwner.attachPath);
|
|
|
|
}
|
|
|
|
if (f == null || !f.exists()) {
|
|
|
|
f = FileLoader.getPathToMessage(message.messageOwner);
|
|
|
|
}
|
|
|
|
if (f != null && f.exists()) {
|
|
|
|
String realMimeType = null;
|
|
|
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
2016-10-11 13:57:01 +02:00
|
|
|
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
2016-06-24 12:27:15 +02:00
|
|
|
MimeTypeMap myMime = MimeTypeMap.getSingleton();
|
|
|
|
int idx = fileName.lastIndexOf('.');
|
|
|
|
if (idx != -1) {
|
|
|
|
String ext = fileName.substring(idx + 1);
|
|
|
|
realMimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase());
|
|
|
|
if (realMimeType == null) {
|
|
|
|
if (message.type == 9 || message.type == 0) {
|
|
|
|
realMimeType = message.getDocument().mime_type;
|
|
|
|
}
|
|
|
|
if (realMimeType == null || realMimeType.length() == 0) {
|
|
|
|
realMimeType = null;
|
|
|
|
}
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
}
|
|
|
|
if (Build.VERSION.SDK_INT >= 24) {
|
|
|
|
intent.setDataAndType(FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", f), realMimeType != null ? realMimeType : "text/plain");
|
2016-06-24 12:27:15 +02:00
|
|
|
} else {
|
2016-10-11 13:57:01 +02:00
|
|
|
intent.setDataAndType(Uri.fromFile(f), realMimeType != null ? realMimeType : "text/plain");
|
2016-06-24 12:27:15 +02:00
|
|
|
}
|
|
|
|
if (realMimeType != null) {
|
|
|
|
try {
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
} catch (Exception e) {
|
2016-10-11 13:57:01 +02:00
|
|
|
if (Build.VERSION.SDK_INT >= 24) {
|
|
|
|
intent.setDataAndType(FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", f), "text/plain");
|
|
|
|
} else {
|
|
|
|
intent.setDataAndType(Uri.fromFile(f), "text/plain");
|
|
|
|
}
|
2016-06-24 12:27:15 +02:00
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
|
|
|
|
public static void setRectToRect(Matrix matrix, RectF src, RectF dst, int rotation, Matrix.ScaleToFit align) {
|
|
|
|
float tx, sx;
|
|
|
|
float ty, sy;
|
|
|
|
if (rotation == 90 || rotation == 270) {
|
|
|
|
sx = dst.height() / src.width();
|
|
|
|
sy = dst.width() / src.height();
|
|
|
|
} else {
|
|
|
|
sx = dst.width() / src.width();
|
|
|
|
sy = dst.height() / src.height();
|
|
|
|
}
|
|
|
|
if (align != Matrix.ScaleToFit.FILL) {
|
|
|
|
if (sx > sy) {
|
|
|
|
sx = sy;
|
|
|
|
} else {
|
|
|
|
sy = sx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tx = -src.left * sx;
|
|
|
|
ty = -src.top * sy;
|
|
|
|
|
|
|
|
matrix.setTranslate(dst.left, dst.top);
|
|
|
|
if (rotation == 90) {
|
|
|
|
matrix.preRotate(90);
|
|
|
|
matrix.preTranslate(0, -dst.width());
|
|
|
|
} else if (rotation == 180) {
|
|
|
|
matrix.preRotate(180);
|
|
|
|
matrix.preTranslate(-dst.width(), -dst.height());
|
|
|
|
} else if (rotation == 270) {
|
|
|
|
matrix.preRotate(270);
|
|
|
|
matrix.preTranslate(-dst.height(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
matrix.preScale(sx, sy);
|
|
|
|
matrix.preTranslate(tx, ty);
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
}
|