2014-07-03 00:39:05 +02:00
|
|
|
|
/*
|
2019-01-23 18:03:33 +01:00
|
|
|
|
* This is the source code of Telegram for Android v. 5.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).
|
|
|
|
|
*
|
2019-01-23 18:03:33 +01:00
|
|
|
|
* Copyright Nikolai Kudashov, 2013-2018.
|
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;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import android.animation.AnimatorListenerAdapter;
|
2016-06-24 12:27:15 +02:00
|
|
|
|
import android.animation.AnimatorSet;
|
|
|
|
|
import android.animation.ObjectAnimator;
|
2022-03-20 21:22:37 +01:00
|
|
|
|
import android.animation.ValueAnimator;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import android.annotation.SuppressLint;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.app.Activity;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
import android.app.KeyguardManager;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.content.ContentResolver;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import android.content.ContentUris;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.content.Context;
|
2022-02-01 14:00:45 +01:00
|
|
|
|
import android.content.ContextWrapper;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import android.content.Intent;
|
2018-08-27 10:33:11 +02:00
|
|
|
|
import android.content.IntentFilter;
|
2017-07-08 18:32:04 +02:00
|
|
|
|
import android.content.SharedPreferences;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.content.pm.ActivityInfo;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import android.content.pm.PackageInfo;
|
2015-10-29 18:10:07 +01:00
|
|
|
|
import android.content.pm.PackageManager;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import android.content.pm.Signature;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.content.res.AssetFileDescriptor;
|
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;
|
2021-12-30 11:52:40 +01:00
|
|
|
|
import android.graphics.BitmapFactory;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
import android.graphics.Canvas;
|
2015-04-09 20:00:14 +02:00
|
|
|
|
import android.graphics.Color;
|
2022-02-15 21:18:49 +01:00
|
|
|
|
import android.graphics.ColorMatrix;
|
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;
|
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;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
import android.os.PowerManager;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import android.os.SystemClock;
|
2022-06-21 04:51:00 +02:00
|
|
|
|
import android.os.Vibrator;
|
2019-08-22 01:53:26 +02:00
|
|
|
|
import android.provider.CallLog;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import android.provider.DocumentsContract;
|
|
|
|
|
import android.provider.MediaStore;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.provider.Settings;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import android.telephony.TelephonyManager;
|
2020-09-30 15:48:47 +02:00
|
|
|
|
import android.text.Layout;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.text.Selection;
|
|
|
|
|
import android.text.Spannable;
|
2014-12-01 18:56:31 +01:00
|
|
|
|
import android.text.SpannableStringBuilder;
|
|
|
|
|
import android.text.Spanned;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
import android.text.SpannedString;
|
2020-09-30 15:48:47 +02:00
|
|
|
|
import android.text.StaticLayout;
|
|
|
|
|
import android.text.TextPaint;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import android.text.TextUtils;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.text.method.LinkMovementMethod;
|
2022-04-16 16:43:17 +02:00
|
|
|
|
import android.text.style.ClickableSpan;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import android.text.style.URLSpan;
|
|
|
|
|
import android.text.util.Linkify;
|
2015-02-26 02:32:51 +01:00
|
|
|
|
import android.util.DisplayMetrics;
|
2014-11-17 03:44:57 +01:00
|
|
|
|
import android.util.StateSet;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.util.TypedValue;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.view.Display;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.view.Gravity;
|
2021-12-07 14:02:02 +01:00
|
|
|
|
import android.view.MotionEvent;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.view.Surface;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
import android.view.TextureView;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.view.View;
|
2022-06-21 04:51:00 +02:00
|
|
|
|
import android.view.ViewConfiguration;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.view.ViewGroup;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import android.view.Window;
|
2020-12-23 08:48:30 +01:00
|
|
|
|
import android.view.WindowInsets;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.view.WindowManager;
|
2019-05-14 14:08:05 +02:00
|
|
|
|
import android.view.accessibility.AccessibilityEvent;
|
|
|
|
|
import android.view.accessibility.AccessibilityManager;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.view.animation.AccelerateInterpolator;
|
2017-07-23 14:56:38 +02:00
|
|
|
|
import android.view.animation.DecelerateInterpolator;
|
|
|
|
|
import android.view.animation.OvershootInterpolator;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import android.view.inputmethod.InputMethodManager;
|
2019-05-14 14:08:05 +02:00
|
|
|
|
import android.view.inputmethod.InputMethodSubtype;
|
2016-06-24 12:27:15 +02:00
|
|
|
|
import android.webkit.MimeTypeMap;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
import android.widget.EdgeEffect;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
import android.widget.HorizontalScrollView;
|
2022-06-21 04:51:00 +02:00
|
|
|
|
import android.widget.ImageView;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.widget.LinearLayout;
|
2014-11-11 23:16:17 +01:00
|
|
|
|
import android.widget.ListView;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import android.widget.ScrollView;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import android.widget.TextView;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
2022-04-16 16:43:17 +02:00
|
|
|
|
import androidx.annotation.NonNull;
|
2022-06-21 04:51:00 +02:00
|
|
|
|
import androidx.core.content.ContextCompat;
|
2021-12-07 14:02:02 +01:00
|
|
|
|
import androidx.core.content.FileProvider;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
import androidx.dynamicanimation.animation.DynamicAnimation;
|
|
|
|
|
import androidx.dynamicanimation.animation.SpringAnimation;
|
|
|
|
|
import androidx.dynamicanimation.animation.SpringForce;
|
2021-12-07 14:02:02 +01:00
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
|
import androidx.viewpager.widget.ViewPager;
|
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import com.android.internal.telephony.ITelephony;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
import com.google.android.gms.auth.api.phone.SmsRetriever;
|
|
|
|
|
import com.google.android.gms.auth.api.phone.SmsRetrieverClient;
|
|
|
|
|
import com.google.android.gms.tasks.Task;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import org.telegram.PhoneFormat.PhoneFormat;
|
2020-10-30 11:26:29 +01:00
|
|
|
|
import org.telegram.messenger.browser.Browser;
|
2015-09-24 22:52:02 +02:00
|
|
|
|
import org.telegram.tgnet.ConnectionsManager;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import org.telegram.tgnet.TLObject;
|
2015-09-24 22:52:02 +02:00
|
|
|
|
import org.telegram.tgnet.TLRPC;
|
2020-07-26 10:03:38 +02:00
|
|
|
|
import org.telegram.ui.ActionBar.ActionBarLayout;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import org.telegram.ui.ActionBar.AlertDialog;
|
2016-04-22 15:49:00 +02:00
|
|
|
|
import org.telegram.ui.ActionBar.BaseFragment;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import org.telegram.ui.ActionBar.BottomSheet;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
import org.telegram.ui.ActionBar.Theme;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import org.telegram.ui.Cells.TextDetailSettingsCell;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
import org.telegram.ui.Components.AlertsCreator;
|
2019-09-10 12:56:11 +02:00
|
|
|
|
import org.telegram.ui.Components.BackgroundGradientDrawable;
|
2022-03-20 21:22:37 +01:00
|
|
|
|
import org.telegram.ui.Components.CubicBezierInterpolator;
|
2020-09-30 15:48:47 +02:00
|
|
|
|
import org.telegram.ui.Components.ForegroundColorSpanThemable;
|
2015-02-26 02:32:51 +01:00
|
|
|
|
import org.telegram.ui.Components.ForegroundDetector;
|
2021-07-30 16:49:55 +02:00
|
|
|
|
import org.telegram.ui.Components.HideViewAfterAnimation;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import org.telegram.ui.Components.LayoutHelper;
|
2021-06-25 02:43:10 +02:00
|
|
|
|
import org.telegram.ui.Components.MotionBackgroundDrawable;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import org.telegram.ui.Components.PickerBottomLayout;
|
2020-07-26 10:03:38 +02:00
|
|
|
|
import org.telegram.ui.Components.RecyclerListView;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import org.telegram.ui.Components.ShareAlert;
|
2014-12-01 18:56:31 +01:00
|
|
|
|
import org.telegram.ui.Components.TypefaceSpan;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
import org.telegram.ui.ThemePreviewActivity;
|
2019-02-08 03:30:32 +01:00
|
|
|
|
import org.telegram.ui.WallpapersListActivity;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import java.io.BufferedReader;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import java.io.ByteArrayInputStream;
|
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;
|
2020-03-30 14:00:09 +02:00
|
|
|
|
import java.io.FileWriter;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import java.io.InputStreamReader;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import java.io.OutputStream;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import java.lang.ref.WeakReference;
|
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;
|
2021-02-23 12:53:38 +01:00
|
|
|
|
import java.net.IDN;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import java.security.cert.CertificateFactory;
|
|
|
|
|
import java.security.cert.X509Certificate;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import java.text.SimpleDateFormat;
|
2014-12-01 18:56:31 +01:00
|
|
|
|
import java.util.ArrayList;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
import java.util.Calendar;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.Comparator;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import java.util.Date;
|
2022-02-01 14:00:45 +01:00
|
|
|
|
import java.util.HashMap;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import java.util.HashSet;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
import java.util.Hashtable;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
import java.util.List;
|
2015-05-21 23:27:27 +02:00
|
|
|
|
import java.util.Locale;
|
2022-06-21 04:51:00 +02:00
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
import java.util.regex.Matcher;
|
2015-11-26 22:04:02 +01:00
|
|
|
|
import java.util.regex.Pattern;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
|
|
|
|
|
public class AndroidUtilities {
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public final static int LIGHT_STATUS_BAR_OVERLAY = 0x0f000000, DARK_STATUS_BAR_OVERLAY = 0x33000000;
|
2014-10-11 13:30:32 +02:00
|
|
|
|
|
2022-06-21 04:51:00 +02:00
|
|
|
|
public final static String TYPEFACE_ROBOTO_MEDIUM = "fonts/rmedium.ttf";
|
|
|
|
|
|
2015-01-02 23:15:07 +01:00
|
|
|
|
private static final Hashtable<String, Typeface> typefaceCache = new Hashtable<>();
|
2022-06-21 04:51:00 +02:00
|
|
|
|
public static float touchSlop;
|
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;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static int navigationBarHeight = 0;
|
2019-05-14 14:08:05 +02:00
|
|
|
|
public static boolean firstConfigurationWas;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
public static float density = 1;
|
|
|
|
|
public static Point displaySize = new Point();
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static float screenRefreshRate = 60;
|
2017-07-08 18:32:04 +02:00
|
|
|
|
public static int roundMessageSize;
|
2021-07-30 16:49:55 +02:00
|
|
|
|
public static int roundPlayingMessageSize;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static int roundMessageInset;
|
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;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
|
2017-07-23 14:56:38 +02:00
|
|
|
|
public static DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
|
2018-07-30 04:07:02 +02:00
|
|
|
|
public static AccelerateInterpolator accelerateInterpolator = new AccelerateInterpolator();
|
2017-07-23 14:56:38 +02:00
|
|
|
|
public static OvershootInterpolator overshootInterpolator = new OvershootInterpolator();
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
private static AccessibilityManager accessibilityManager;
|
2022-06-21 04:51:00 +02:00
|
|
|
|
private static Vibrator vibrator;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
|
|
|
|
|
private static Boolean isTablet = null, isSmallScreen = null;
|
2015-09-24 22:52:02 +02:00
|
|
|
|
private static int adjustOwnerClassGuid = 0;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
private static int altFocusableClassGuid = 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;
|
|
|
|
|
|
2021-04-14 03:44:46 +02:00
|
|
|
|
public static final RectF rectTmp = new RectF();
|
2022-01-18 21:51:58 +01:00
|
|
|
|
public static final Rect rectTmp2 = new Rect();
|
2021-04-14 03:44:46 +02:00
|
|
|
|
|
2015-11-26 22:04:02 +01:00
|
|
|
|
public static Pattern WEB_URL = null;
|
2021-06-25 02:43:10 +02:00
|
|
|
|
public static Pattern BAD_CHARS_PATTERN = null;
|
|
|
|
|
public static Pattern BAD_CHARS_MESSAGE_PATTERN = null;
|
2021-07-30 16:49:55 +02:00
|
|
|
|
public static Pattern BAD_CHARS_MESSAGE_LONG_PATTERN = null;
|
2022-04-16 16:43:17 +02:00
|
|
|
|
private static Pattern singleTagPatter = null;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
|
2015-11-26 22:04:02 +01:00
|
|
|
|
static {
|
|
|
|
|
try {
|
|
|
|
|
final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
|
2021-06-25 02:43:10 +02:00
|
|
|
|
BAD_CHARS_PATTERN = Pattern.compile("[\u2500-\u25ff]");
|
2021-07-30 16:49:55 +02:00
|
|
|
|
BAD_CHARS_MESSAGE_LONG_PATTERN = Pattern.compile("[\u0300-\u036f\u2066-\u2067]+");
|
|
|
|
|
BAD_CHARS_MESSAGE_PATTERN = Pattern.compile("[\u2066-\u2067]+");
|
2015-11-26 22:04:02 +01:00
|
|
|
|
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(
|
2019-12-31 14:08:08 +01:00
|
|
|
|
"((?:(http|https|Http|Https|ton|tg):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
|
2015-11-26 22:04:02 +01:00
|
|
|
|
+ "\\,\\;\\?\\&\\=]|(?:\\%[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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-11-26 22:04:02 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
private static int[] documentIcons = {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
R.drawable.media_doc_blue,
|
|
|
|
|
R.drawable.media_doc_green,
|
|
|
|
|
R.drawable.media_doc_red,
|
|
|
|
|
R.drawable.media_doc_yellow
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
private static int[] documentMediaIcons = {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
R.drawable.media_doc_blue_b,
|
|
|
|
|
R.drawable.media_doc_green_b,
|
|
|
|
|
R.drawable.media_doc_red_b,
|
|
|
|
|
R.drawable.media_doc_yellow_b
|
|
|
|
|
};
|
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
|
public static final String STICKERS_PLACEHOLDER_PACK_NAME = "tg_placeholders_android";
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
private static boolean containsUnsupportedCharacters(String text) {
|
|
|
|
|
if (text.contains("\u202C")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (text.contains("\u202D")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (text.contains("\u202E")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-06-25 02:43:10 +02:00
|
|
|
|
try {
|
|
|
|
|
if (BAD_CHARS_PATTERN.matcher(text).find()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-12-31 14:08:08 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 16:49:55 +02:00
|
|
|
|
public static String getSafeString(String str) {
|
|
|
|
|
try {
|
|
|
|
|
return BAD_CHARS_MESSAGE_PATTERN.matcher(str).replaceAll("\u200C");
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 11:26:29 +01:00
|
|
|
|
public static CharSequence ellipsizeCenterEnd(CharSequence str, String query, int availableWidth, TextPaint textPaint, int maxSymbols) {
|
2020-09-30 15:48:47 +02:00
|
|
|
|
try {
|
|
|
|
|
int lastIndex = str.length();
|
2020-10-30 11:26:29 +01:00
|
|
|
|
int startHighlightedIndex = str.toString().toLowerCase().indexOf(query);
|
|
|
|
|
|
|
|
|
|
if (lastIndex > maxSymbols) {
|
|
|
|
|
str = str.subSequence(Math.max(0, startHighlightedIndex - maxSymbols / 2), Math.min(lastIndex, startHighlightedIndex + maxSymbols / 2));
|
|
|
|
|
startHighlightedIndex -= Math.max(0, startHighlightedIndex - maxSymbols / 2);
|
|
|
|
|
lastIndex = str.length();
|
|
|
|
|
}
|
|
|
|
|
StaticLayout staticLayout = new StaticLayout(str, textPaint, Integer.MAX_VALUE, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
|
2020-12-23 08:48:30 +01:00
|
|
|
|
float endOfTextX = staticLayout.getLineWidth(0);
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if (endOfTextX + textPaint.measureText("...") < availableWidth) {
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int i = startHighlightedIndex + 1;
|
|
|
|
|
while (i < str.length() - 1 && !Character.isWhitespace(str.charAt(i))) {
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
int endHighlightedIndex = i;
|
|
|
|
|
|
|
|
|
|
float endOfHighlight = staticLayout.getPrimaryHorizontal(endHighlightedIndex);
|
2020-12-23 08:48:30 +01:00
|
|
|
|
if (staticLayout.isRtlCharAt(endHighlightedIndex)) {
|
|
|
|
|
endOfHighlight = endOfTextX - endOfHighlight;
|
|
|
|
|
}
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if (endOfHighlight < availableWidth) {
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
float x = endOfHighlight - availableWidth + textPaint.measureText("...") * 2 + availableWidth * 0.1f;
|
|
|
|
|
if (str.length() - endHighlightedIndex > 20) {
|
|
|
|
|
x += availableWidth * 0.1f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (x > 0) {
|
|
|
|
|
int charOf = staticLayout.getOffsetForHorizontal(0, x);
|
|
|
|
|
int k = 0;
|
|
|
|
|
if (charOf > str.length() - 1) {
|
|
|
|
|
charOf = str.length() - 1;
|
|
|
|
|
}
|
|
|
|
|
while (!Character.isWhitespace(str.charAt(charOf)) && k < 10) {
|
|
|
|
|
k++;
|
|
|
|
|
charOf++;
|
|
|
|
|
if (charOf > str.length() - 1) {
|
|
|
|
|
charOf = staticLayout.getOffsetForHorizontal(0, x);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CharSequence sub;
|
|
|
|
|
if (k >= 10) {
|
|
|
|
|
x = staticLayout.getPrimaryHorizontal(startHighlightedIndex + 1) - availableWidth * 0.3f;
|
|
|
|
|
sub = str.subSequence(staticLayout.getOffsetForHorizontal(0, x), str.length());
|
|
|
|
|
} else {
|
2020-10-05 00:13:31 +02:00
|
|
|
|
if (charOf > 0 && charOf < str.length() - 2 && Character.isWhitespace(str.charAt(charOf))) {
|
|
|
|
|
charOf++;
|
2020-09-30 15:48:47 +02:00
|
|
|
|
}
|
|
|
|
|
sub = str.subSequence(charOf, str.length());
|
|
|
|
|
}
|
|
|
|
|
return SpannableStringBuilder.valueOf("...").append(sub);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
|
public static CharSequence highlightText(CharSequence str, ArrayList<String> query, Theme.ResourcesProvider resourcesProvider) {
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if (query == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
int emptyCount = 0;
|
|
|
|
|
for (int i = 0; i < query.size(); i++) {
|
2021-09-20 07:54:41 +02:00
|
|
|
|
CharSequence strTmp = highlightText(str, query.get(i), resourcesProvider);
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if (strTmp != null) {
|
|
|
|
|
str = strTmp;
|
|
|
|
|
} else {
|
|
|
|
|
emptyCount++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (emptyCount == query.size()) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
|
public static CharSequence highlightText(CharSequence str, String query, Theme.ResourcesProvider resourcesProvider) {
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if (TextUtils.isEmpty(query) || TextUtils.isEmpty(str)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
String s = str.toString().toLowerCase();
|
|
|
|
|
SpannableStringBuilder spannableStringBuilder = SpannableStringBuilder.valueOf(str);
|
|
|
|
|
int i = s.indexOf(query);
|
|
|
|
|
while (i >= 0) {
|
2020-10-02 23:48:16 +02:00
|
|
|
|
try {
|
2021-09-20 07:54:41 +02:00
|
|
|
|
spannableStringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider), i, Math.min(i + query.length(), str.length()), 0);
|
2020-10-02 23:48:16 +02:00
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
2020-09-30 15:48:47 +02:00
|
|
|
|
i = s.indexOf(query, i + 1);
|
|
|
|
|
}
|
|
|
|
|
return spannableStringBuilder;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 08:48:30 +01:00
|
|
|
|
public static Activity findActivity(Context context) {
|
|
|
|
|
if (context instanceof Activity) {
|
|
|
|
|
return (Activity) context;
|
|
|
|
|
}
|
2022-02-01 14:00:45 +01:00
|
|
|
|
if (context instanceof ContextWrapper) {
|
|
|
|
|
return findActivity(((ContextWrapper) context).getBaseContext());
|
2020-12-23 08:48:30 +01:00
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-16 16:43:17 +02:00
|
|
|
|
public static CharSequence replaceSingleTag(String str, Runnable runnable) {
|
|
|
|
|
int startIndex = str.indexOf("**");
|
|
|
|
|
int endIndex = str.indexOf("**", startIndex + 1);
|
|
|
|
|
str = str.replace("**", "");
|
|
|
|
|
int index = -1;
|
|
|
|
|
int len = 0;
|
|
|
|
|
if (startIndex >= 0 && endIndex >= 0 && endIndex - startIndex > 2) {
|
|
|
|
|
len = endIndex - startIndex - 2;
|
|
|
|
|
index = startIndex;
|
|
|
|
|
}
|
|
|
|
|
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str);
|
|
|
|
|
if (index >= 0) {
|
|
|
|
|
spannableStringBuilder.setSpan(new ClickableSpan() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void updateDrawState(@NonNull TextPaint ds) {
|
|
|
|
|
super.updateDrawState(ds);
|
|
|
|
|
ds.setUnderlineText(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(@NonNull View view) {
|
|
|
|
|
runnable.run();
|
|
|
|
|
}
|
|
|
|
|
}, index, index + len, 0);
|
|
|
|
|
}
|
|
|
|
|
return spannableStringBuilder;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-21 04:51:00 +02:00
|
|
|
|
public static void recycleBitmaps(ArrayList<Bitmap> bitmapToRecycle) {
|
|
|
|
|
if (bitmapToRecycle != null && !bitmapToRecycle.isEmpty()) {
|
|
|
|
|
AndroidUtilities.runOnUIThread(() -> NotificationCenter.getInstance(UserConfig.selectedAccount).doOnIdle(() -> {
|
|
|
|
|
for (int i = 0; i < bitmapToRecycle.size(); i++) {
|
|
|
|
|
Bitmap bitmap = bitmapToRecycle.get(i);
|
|
|
|
|
if (bitmap != null && !bitmap.isRecycled()) {
|
|
|
|
|
try {
|
|
|
|
|
bitmap.recycle();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}), 36);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
private static class LinkSpec {
|
|
|
|
|
String url;
|
|
|
|
|
int start;
|
|
|
|
|
int end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String makeUrl(String url, String[] prefixes, Matcher matcher) {
|
|
|
|
|
boolean hasPrefix = false;
|
|
|
|
|
for (int i = 0; i < prefixes.length; i++) {
|
|
|
|
|
if (url.regionMatches(true, 0, prefixes[i], 0, prefixes[i].length())) {
|
|
|
|
|
hasPrefix = true;
|
|
|
|
|
if (!url.regionMatches(false, 0, prefixes[i], 0, prefixes[i].length())) {
|
|
|
|
|
url = prefixes[i] + url.substring(prefixes[i].length());
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!hasPrefix && prefixes.length > 0) {
|
|
|
|
|
url = prefixes[0] + url;
|
|
|
|
|
}
|
|
|
|
|
return url;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 11:26:29 +01:00
|
|
|
|
private static void gatherLinks(ArrayList<LinkSpec> links, Spannable s, Pattern pattern, String[] schemes, Linkify.MatchFilter matchFilter, boolean internalOnly) {
|
2021-03-19 11:25:58 +01:00
|
|
|
|
if (TextUtils.indexOf(s, '─') >= 0) {
|
|
|
|
|
s = new SpannableStringBuilder(s.toString().replace('─', ' '));
|
|
|
|
|
}
|
2019-12-31 14:08:08 +01:00
|
|
|
|
Matcher m = pattern.matcher(s);
|
|
|
|
|
while (m.find()) {
|
|
|
|
|
int start = m.start();
|
|
|
|
|
int end = m.end();
|
|
|
|
|
|
|
|
|
|
if (matchFilter == null || matchFilter.acceptMatch(s, start, end)) {
|
|
|
|
|
LinkSpec spec = new LinkSpec();
|
|
|
|
|
|
2020-10-30 11:26:29 +01:00
|
|
|
|
String url = makeUrl(m.group(0), schemes, m);
|
2020-10-30 13:41:45 +01:00
|
|
|
|
if (internalOnly && !Browser.isInternalUrl(url, true, null)) {
|
2020-10-30 11:26:29 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
spec.url = url;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
spec.start = start;
|
|
|
|
|
spec.end = end;
|
|
|
|
|
|
|
|
|
|
links.add(spec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static final Linkify.MatchFilter sUrlMatchFilter = (s, start, end) -> {
|
|
|
|
|
if (start == 0) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (s.charAt(start - 1) == '@') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public static boolean addLinks(Spannable text, int mask) {
|
2020-10-30 11:26:29 +01:00
|
|
|
|
return addLinks(text, mask, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean addLinks(Spannable text, int mask, boolean internalOnly) {
|
|
|
|
|
if (text == null || containsUnsupportedCharacters(text.toString()) || mask == 0) {
|
2019-12-31 14:08:08 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
final URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class);
|
|
|
|
|
for (int i = old.length - 1; i >= 0; i--) {
|
|
|
|
|
text.removeSpan(old[i]);
|
|
|
|
|
}
|
|
|
|
|
final ArrayList<LinkSpec> links = new ArrayList<>();
|
2020-10-30 11:26:29 +01:00
|
|
|
|
if (!internalOnly && (mask & Linkify.PHONE_NUMBERS) != 0) {
|
2019-12-31 14:08:08 +01:00
|
|
|
|
Linkify.addLinks(text, Linkify.PHONE_NUMBERS);
|
|
|
|
|
}
|
|
|
|
|
if ((mask & Linkify.WEB_URLS) != 0) {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
gatherLinks(links, text, LinkifyPort.WEB_URL, new String[]{"http://", "https://", "tg://"}, sUrlMatchFilter, internalOnly);
|
2019-12-31 14:08:08 +01:00
|
|
|
|
}
|
|
|
|
|
pruneOverlaps(links);
|
|
|
|
|
if (links.size() == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-05-01 04:08:26 +02:00
|
|
|
|
for (int a = 0, N = links.size(); a < N; a++) {
|
|
|
|
|
LinkSpec link = links.get(a);
|
|
|
|
|
URLSpan[] oldSpans = text.getSpans(link.start, link.end, URLSpan.class);
|
|
|
|
|
if (oldSpans != null && oldSpans.length > 0) {
|
|
|
|
|
for (int b = 0; b < oldSpans.length; b++) {
|
|
|
|
|
text.removeSpan(oldSpans[b]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-31 14:08:08 +01:00
|
|
|
|
text.setSpan(new URLSpan(link.url), link.start, link.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void pruneOverlaps(ArrayList<LinkSpec> links) {
|
|
|
|
|
Comparator<LinkSpec> c = (a, b) -> {
|
|
|
|
|
if (a.start < b.start) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (a.start > b.start) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (a.end < b.end) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (a.end > b.end) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Collections.sort(links, c);
|
|
|
|
|
|
|
|
|
|
int len = links.size();
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
while (i < len - 1) {
|
|
|
|
|
LinkSpec a = links.get(i);
|
|
|
|
|
LinkSpec b = links.get(i + 1);
|
|
|
|
|
int remove = -1;
|
|
|
|
|
|
|
|
|
|
if ((a.start <= b.start) && (a.end > b.start)) {
|
|
|
|
|
if (b.end <= a.end) {
|
|
|
|
|
remove = i + 1;
|
|
|
|
|
} else if ((a.end - a.start) > (b.end - b.start)) {
|
|
|
|
|
remove = i + 1;
|
|
|
|
|
} else if ((a.end - a.start) < (b.end - b.start)) {
|
|
|
|
|
remove = i;
|
|
|
|
|
}
|
|
|
|
|
if (remove != -1) {
|
|
|
|
|
links.remove(remove);
|
|
|
|
|
len--;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void fillStatusBarHeight(Context context) {
|
|
|
|
|
if (context == null || AndroidUtilities.statusBarHeight > 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-11-05 11:06:49 +01:00
|
|
|
|
AndroidUtilities.statusBarHeight = getStatusBarHeight(context);
|
2022-03-11 17:49:54 +01:00
|
|
|
|
AndroidUtilities.navigationBarHeight = getNavigationBarHeight(context);
|
2021-11-05 11:06:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getStatusBarHeight(Context context) {
|
2019-12-31 14:08:08 +01:00
|
|
|
|
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
|
2021-11-05 11:06:49 +01:00
|
|
|
|
return resourceId > 0 ? context.getResources().getDimensionPixelSize(resourceId) : 0;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
private static int getNavigationBarHeight(Context context) {
|
|
|
|
|
int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
|
|
|
|
|
return resourceId > 0 ? context.getResources().getDimensionPixelSize(resourceId) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static int getThumbForNameOrMime(String name, String mime, boolean media) {
|
|
|
|
|
if (name != null && name.length() != 0) {
|
|
|
|
|
int color = -1;
|
|
|
|
|
if (name.contains(".doc") || name.contains(".txt") || name.contains(".psd")) {
|
|
|
|
|
color = 0;
|
|
|
|
|
} else if (name.contains(".xls") || name.contains(".csv")) {
|
|
|
|
|
color = 1;
|
|
|
|
|
} else if (name.contains(".pdf") || name.contains(".ppt") || name.contains(".key")) {
|
|
|
|
|
color = 2;
|
|
|
|
|
} else if (name.contains(".zip") || name.contains(".rar") || name.contains(".ai") || name.contains(".mp3") || name.contains(".mov") || name.contains(".avi")) {
|
|
|
|
|
color = 3;
|
|
|
|
|
}
|
|
|
|
|
if (color == -1) {
|
|
|
|
|
int idx;
|
|
|
|
|
String ext = (idx = name.lastIndexOf('.')) == -1 ? "" : name.substring(idx + 1);
|
|
|
|
|
if (ext.length() != 0) {
|
|
|
|
|
color = ext.charAt(0) % documentIcons.length;
|
|
|
|
|
} else {
|
|
|
|
|
color = name.charAt(0) % documentIcons.length;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return media ? documentMediaIcons[color] : documentIcons[color];
|
|
|
|
|
}
|
|
|
|
|
return media ? documentMediaIcons[0] : documentIcons[0];
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 19:26:53 +01:00
|
|
|
|
public static int calcBitmapColor(Bitmap bitmap) {
|
|
|
|
|
try {
|
|
|
|
|
Bitmap b = Bitmaps.createScaledBitmap(bitmap, 1, 1, true);
|
|
|
|
|
if (b != null) {
|
|
|
|
|
int bitmapColor = b.getPixel(0, 0);
|
|
|
|
|
if (bitmap != b) {
|
|
|
|
|
b.recycle();
|
|
|
|
|
}
|
|
|
|
|
return bitmapColor;
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-22 15:49:00 +02:00
|
|
|
|
public static int[] calcDrawableColor(Drawable drawable) {
|
|
|
|
|
int bitmapColor = 0xff000000;
|
2019-05-14 14:08:05 +02:00
|
|
|
|
int[] result = new int[4];
|
2016-04-22 15:49:00 +02:00
|
|
|
|
try {
|
|
|
|
|
if (drawable instanceof BitmapDrawable) {
|
|
|
|
|
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
|
2020-02-13 19:26:53 +01:00
|
|
|
|
bitmapColor = calcBitmapColor(bitmap);
|
2016-04-22 15:49:00 +02:00
|
|
|
|
} else if (drawable instanceof ColorDrawable) {
|
2016-06-24 12:27:15 +02:00
|
|
|
|
bitmapColor = ((ColorDrawable) drawable).getColor();
|
2019-09-10 12:56:11 +02:00
|
|
|
|
} else if (drawable instanceof BackgroundGradientDrawable) {
|
|
|
|
|
int[] colors = ((BackgroundGradientDrawable) drawable).getColorsList();
|
2019-12-31 14:08:08 +01:00
|
|
|
|
if (colors != null) {
|
|
|
|
|
if (colors.length > 1) {
|
|
|
|
|
bitmapColor = getAverageColor(colors[0], colors[1]);
|
|
|
|
|
} else if (colors.length > 0) {
|
|
|
|
|
bitmapColor = colors[0];
|
|
|
|
|
}
|
2019-09-10 12:56:11 +02:00
|
|
|
|
}
|
2021-06-25 02:43:10 +02:00
|
|
|
|
} else if (drawable instanceof MotionBackgroundDrawable) {
|
|
|
|
|
result[0] = result[2] = Color.argb(0x2D, 0, 0, 0);
|
|
|
|
|
result[1] = result[3] = Color.argb(0x3D, 0, 0, 0);
|
|
|
|
|
return result;
|
2016-04-22 15:49:00 +02:00
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2016-04-22 15:49:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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]));
|
2019-01-23 18:03:33 +01:00
|
|
|
|
double v = Math.max(0, hsv[2] * 0.65);
|
2019-05-14 14:08:05 +02:00
|
|
|
|
int[] rgb = hsvToRgb(hsv[0], hsv[1], v);
|
2016-04-22 15:49:00 +02:00
|
|
|
|
result[0] = Color.argb(0x66, rgb[0], rgb[1], rgb[2]);
|
|
|
|
|
result[1] = Color.argb(0x88, rgb[0], rgb[1], rgb[2]);
|
2019-01-23 18:03:33 +01:00
|
|
|
|
|
|
|
|
|
double v2 = Math.max(0, hsv[2] * 0.72);
|
|
|
|
|
rgb = hsvToRgb(hsv[0], hsv[1], v2);
|
|
|
|
|
result[2] = Color.argb(0x66, rgb[0], rgb[1], rgb[2]);
|
|
|
|
|
result[3] = Color.argb(0x88, rgb[0], rgb[1], rgb[2]);
|
2016-04-22 15:49:00 +02:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static double[] rgbToHsv(int color) {
|
|
|
|
|
return rgbToHsv(Color.red(color), Color.green(color), Color.blue(color));
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 12:56:11 +02:00
|
|
|
|
public static double[] rgbToHsv(int r, int g, int b) {
|
2016-04-22 15:49:00 +02:00
|
|
|
|
double rf = r / 255.0;
|
|
|
|
|
double gf = g / 255.0;
|
|
|
|
|
double bf = b / 255.0;
|
2020-07-26 10:03:38 +02:00
|
|
|
|
double max = (rf > gf && rf > bf) ? rf : Math.max(gf, bf);
|
|
|
|
|
double min = (rf < gf && rf < bf) ? rf : Math.min(gf, bf);
|
2016-04-22 15:49:00 +02:00
|
|
|
|
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};
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static int hsvToColor(double h, double s, double v) {
|
|
|
|
|
int[] rgb = hsvToRgb(h, s, v);
|
|
|
|
|
return Color.argb(0xff, rgb[0], rgb[1], rgb[2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int[] hsvToRgb(double h, double s, double v) {
|
2016-04-22 15:49:00 +02:00
|
|
|
|
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)};
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static void adjustSaturationColorMatrix(ColorMatrix colorMatrix, float saturation) {
|
|
|
|
|
if (colorMatrix == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
float x = 1 + saturation;
|
|
|
|
|
final float lumR = 0.3086f;
|
|
|
|
|
final float lumG = 0.6094f;
|
|
|
|
|
final float lumB = 0.0820f;
|
|
|
|
|
|
|
|
|
|
colorMatrix.postConcat(new ColorMatrix(new float[] {
|
|
|
|
|
lumR*(1-x)+x,lumG*(1-x),lumB*(1-x),0,0,
|
|
|
|
|
lumR*(1-x),lumG*(1-x)+x,lumB*(1-x),0,0,
|
|
|
|
|
lumR*(1-x),lumG*(1-x),lumB*(1-x)+x,0,0,
|
|
|
|
|
0,0,0,1,0
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
public static void adjustBrightnessColorMatrix(ColorMatrix colorMatrix, float brightness) {
|
|
|
|
|
if (colorMatrix == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
brightness *= 255;
|
|
|
|
|
colorMatrix.postConcat(new ColorMatrix(new float[] {
|
|
|
|
|
1,0,0,0,brightness,
|
|
|
|
|
0,1,0,0,brightness,
|
|
|
|
|
0,0,1,0,brightness,
|
|
|
|
|
0,0,0,1,0
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
public static void multiplyBrightnessColorMatrix(ColorMatrix colorMatrix, float v) {
|
2022-02-15 21:18:49 +01:00
|
|
|
|
if (colorMatrix == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-03-11 17:49:54 +01:00
|
|
|
|
colorMatrix.postConcat(new ColorMatrix(new float[] {
|
|
|
|
|
v,0,0,0,0,
|
|
|
|
|
0,v,0,0,0,
|
|
|
|
|
0,0,v,0,0,
|
|
|
|
|
0,0,0,1,0
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Bitmap snapshotView(View v) {
|
|
|
|
|
Bitmap bm = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
|
|
|
|
|
Canvas canvas = new Canvas(bm);
|
|
|
|
|
v.draw(canvas);
|
|
|
|
|
|
|
|
|
|
int[] loc = new int[2];
|
|
|
|
|
v.getLocationInWindow(loc);
|
|
|
|
|
snapshotTextureViews(loc[0], loc[1], loc, canvas, v);
|
|
|
|
|
|
|
|
|
|
return bm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void snapshotTextureViews(int rootX, int rootY, int[] loc, Canvas canvas, View v) {
|
|
|
|
|
if (v instanceof TextureView) {
|
|
|
|
|
TextureView tv = (TextureView) v;
|
|
|
|
|
tv.getLocationInWindow(loc);
|
|
|
|
|
|
|
|
|
|
Bitmap textureSnapshot = tv.getBitmap();
|
|
|
|
|
if (textureSnapshot != null) {
|
|
|
|
|
canvas.save();
|
|
|
|
|
canvas.drawBitmap(textureSnapshot, loc[0] - rootX, loc[1] - rootY, null);
|
|
|
|
|
canvas.restore();
|
|
|
|
|
textureSnapshot.recycle();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (v instanceof ViewGroup) {
|
|
|
|
|
ViewGroup vg = (ViewGroup) v;
|
|
|
|
|
for (int i = 0; i < vg.getChildCount(); i++) {
|
|
|
|
|
snapshotTextureViews(rootX, rootY, loc, canvas, vg.getChildAt(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void requestAltFocusable(Activity activity, int classGuid) {
|
|
|
|
|
if (activity == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
|
|
|
|
|
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
|
|
|
|
|
altFocusableClassGuid = classGuid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void removeAltFocusable(Activity activity, int classGuid) {
|
|
|
|
|
if (activity == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (altFocusableClassGuid == classGuid) {
|
|
|
|
|
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
|
|
|
|
|
}
|
2022-02-15 21:18:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
|
public static void requestAdjustResize(Activity activity, int classGuid) {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
if (activity == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
requestAdjustResize(activity.getWindow(), classGuid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void requestAdjustResize(Window window, int classGuid) {
|
|
|
|
|
if (window == null || isTablet()) {
|
2015-09-24 22:52:02 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-21 04:51:00 +02:00
|
|
|
|
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
2015-09-24 22:52:02 +02:00
|
|
|
|
adjustOwnerClassGuid = classGuid;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 11:26:29 +01:00
|
|
|
|
public static void requestAdjustNothing(Activity activity, int classGuid) {
|
|
|
|
|
if (activity == null || isTablet()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
|
|
|
|
|
adjustOwnerClassGuid = classGuid;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
public static void setAdjustResizeToNothing(Activity activity, int classGuid) {
|
|
|
|
|
if (activity == null || isTablet()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if (adjustOwnerClassGuid == 0 || adjustOwnerClassGuid == classGuid) {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-24 22:52:02 +02:00
|
|
|
|
public static void removeAdjustResize(Activity activity, int classGuid) {
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if (activity == null || isTablet()) {
|
2015-09-24 22:52:02 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (adjustOwnerClassGuid == classGuid) {
|
|
|
|
|
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-30 14:00:09 +02:00
|
|
|
|
public static void createEmptyFile(File f) {
|
|
|
|
|
try {
|
|
|
|
|
if (f.exists()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
FileWriter writer = new FileWriter(f);
|
|
|
|
|
writer.flush();
|
|
|
|
|
writer.close();
|
|
|
|
|
} catch (Throwable e) {
|
2022-02-12 06:22:45 +01:00
|
|
|
|
FileLog.e(e, false);
|
2020-03-30 14:00:09 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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());
|
2019-01-23 18:03:33 +01:00
|
|
|
|
builder.setMessage(LocaleController.getString("InstallGoogleMaps", R.string.InstallGoogleMaps));
|
|
|
|
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, 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 e1) {
|
|
|
|
|
FileLog.e(e1);
|
2016-04-22 15:49:00 +02:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
|
|
|
|
fragment.showDialog(builder.create());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static int[] toIntArray(List<Integer> integers) {
|
|
|
|
|
int[] ret = new int[integers.size()];
|
|
|
|
|
for (int i = 0; i < ret.length; i++) {
|
|
|
|
|
ret[i] = integers.get(i);
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-25 23:49:47 +02:00
|
|
|
|
public static boolean isInternalUri(Uri uri) {
|
2020-09-30 15:48:47 +02:00
|
|
|
|
return isInternalUri(uri, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isInternalUri(int fd) {
|
|
|
|
|
return isInternalUri(null, fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static boolean isInternalUri(Uri uri, int fd) {
|
|
|
|
|
String pathString;
|
|
|
|
|
if (uri != null) {
|
|
|
|
|
pathString = uri.getPath();
|
|
|
|
|
if (pathString == null) {
|
|
|
|
|
return false;
|
2019-02-08 03:30:32 +01:00
|
|
|
|
}
|
2020-09-30 15:48:47 +02:00
|
|
|
|
// Allow sending VoIP logs from cache/voip_logs
|
|
|
|
|
if (pathString.matches(Pattern.quote(new File(ApplicationLoader.applicationContext.getCacheDir(), "voip_logs").getAbsolutePath()) + "/\\d+\\.log")) {
|
|
|
|
|
return false;
|
2019-09-10 12:56:11 +02:00
|
|
|
|
}
|
2020-09-30 15:48:47 +02:00
|
|
|
|
int tries = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
if (pathString != null && pathString.length() > 4096) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
String newPath;
|
|
|
|
|
try {
|
|
|
|
|
newPath = Utilities.readlink(pathString);
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (newPath == null || newPath.equals(pathString)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pathString = newPath;
|
|
|
|
|
tries++;
|
|
|
|
|
if (tries >= 10) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-05-25 23:49:47 +02:00
|
|
|
|
}
|
2020-09-30 15:48:47 +02:00
|
|
|
|
} else {
|
|
|
|
|
pathString = "";
|
|
|
|
|
int tries = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
if (pathString != null && pathString.length() > 4096) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
String newPath;
|
|
|
|
|
try {
|
|
|
|
|
newPath = Utilities.readlinkFd(fd);
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (newPath == null || newPath.equals(pathString)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pathString = newPath;
|
|
|
|
|
tries++;
|
|
|
|
|
if (tries >= 10) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-02-08 03:30:32 +01:00
|
|
|
|
}
|
2016-05-25 23:49:47 +02:00
|
|
|
|
}
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-10 12:56:11 +02:00
|
|
|
|
if (pathString.endsWith(".attheme")) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
|
return pathString != null && pathString.toLowerCase().contains("/data/data/" + ApplicationLoader.applicationContext.getPackageName());
|
2016-05-25 23:49:47 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
@SuppressLint("WrongConstant")
|
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();
|
2017-03-31 01:58:05 +02:00
|
|
|
|
WindowManager manager = (WindowManager) activity.getSystemService(Activity.WINDOW_SERVICE);
|
2014-07-03 00:39:05 +02:00
|
|
|
|
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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
@SuppressLint("WrongConstant")
|
2014-07-03 00:39:05 +02:00
|
|
|
|
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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
|
private static class VcardData {
|
|
|
|
|
String name;
|
|
|
|
|
ArrayList<String> phones = new ArrayList<>();
|
|
|
|
|
StringBuilder vcard = new StringBuilder();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class VcardItem {
|
|
|
|
|
public ArrayList<String> vcardData = new ArrayList<>();
|
|
|
|
|
public String fullData = "";
|
|
|
|
|
public int type;
|
|
|
|
|
public boolean checked = true;
|
|
|
|
|
|
|
|
|
|
public String[] getRawValue() {
|
|
|
|
|
int idx = fullData.indexOf(':');
|
|
|
|
|
if (idx < 0) {
|
|
|
|
|
return new String[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String valueType = fullData.substring(0, idx);
|
2019-05-14 14:08:05 +02:00
|
|
|
|
String value = fullData.substring(idx + 1);
|
2018-07-30 04:07:02 +02:00
|
|
|
|
|
|
|
|
|
String nameEncoding = null;
|
|
|
|
|
String nameCharset = "UTF-8";
|
|
|
|
|
String[] params = valueType.split(";");
|
|
|
|
|
for (int a = 0; a < params.length; a++) {
|
|
|
|
|
String[] args2 = params[a].split("=");
|
|
|
|
|
if (args2.length != 2) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args2[0].equals("CHARSET")) {
|
|
|
|
|
nameCharset = args2[1];
|
|
|
|
|
} else if (args2[0].equals("ENCODING")) {
|
|
|
|
|
nameEncoding = args2[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
String[] args = value.split(";");
|
|
|
|
|
boolean added = false;
|
|
|
|
|
for (int a = 0; a < args.length; a++) {
|
|
|
|
|
if (TextUtils.isEmpty(args[a])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (nameEncoding != null && nameEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
|
|
|
|
|
byte[] bytes = decodeQuotedPrintable(getStringBytes(args[a]));
|
|
|
|
|
if (bytes != null && bytes.length != 0) {
|
|
|
|
|
try {
|
|
|
|
|
args[a] = new String(bytes, nameCharset);
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return args;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getValue(boolean format) {
|
|
|
|
|
StringBuilder result = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
int idx = fullData.indexOf(':');
|
|
|
|
|
if (idx < 0) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result.length() > 0) {
|
|
|
|
|
result.append(", ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String valueType = fullData.substring(0, idx);
|
2019-05-14 14:08:05 +02:00
|
|
|
|
String value = fullData.substring(idx + 1);
|
2018-07-30 04:07:02 +02:00
|
|
|
|
|
|
|
|
|
String nameEncoding = null;
|
|
|
|
|
String nameCharset = "UTF-8";
|
|
|
|
|
String[] params = valueType.split(";");
|
|
|
|
|
for (int a = 0; a < params.length; a++) {
|
|
|
|
|
String[] args2 = params[a].split("=");
|
|
|
|
|
if (args2.length != 2) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args2[0].equals("CHARSET")) {
|
|
|
|
|
nameCharset = args2[1];
|
|
|
|
|
} else if (args2[0].equals("ENCODING")) {
|
|
|
|
|
nameEncoding = args2[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
String[] args = value.split(";");
|
|
|
|
|
boolean added = false;
|
|
|
|
|
for (int a = 0; a < args.length; a++) {
|
|
|
|
|
if (TextUtils.isEmpty(args[a])) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (nameEncoding != null && nameEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
|
|
|
|
|
byte[] bytes = decodeQuotedPrintable(getStringBytes(args[a]));
|
|
|
|
|
if (bytes != null && bytes.length != 0) {
|
|
|
|
|
try {
|
|
|
|
|
args[a] = new String(bytes, nameCharset);
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (added && result.length() > 0) {
|
|
|
|
|
result.append(" ");
|
|
|
|
|
}
|
|
|
|
|
result.append(args[a]);
|
|
|
|
|
if (!added) {
|
|
|
|
|
added = args[a].length() > 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (format) {
|
|
|
|
|
if (type == 0) {
|
|
|
|
|
return PhoneFormat.getInstance().format(result.toString());
|
|
|
|
|
} else if (type == 5) {
|
|
|
|
|
String[] date = result.toString().split("T");
|
|
|
|
|
if (date.length > 0) {
|
|
|
|
|
date = date[0].split("-");
|
|
|
|
|
if (date.length == 3) {
|
|
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
|
|
calendar.set(Calendar.YEAR, Utilities.parseInt(date[0]));
|
|
|
|
|
calendar.set(Calendar.MONTH, Utilities.parseInt(date[1]) - 1);
|
|
|
|
|
calendar.set(Calendar.DAY_OF_MONTH, Utilities.parseInt(date[2]));
|
|
|
|
|
return LocaleController.getInstance().formatterYearMax.format(calendar.getTime());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getRawType(boolean first) {
|
|
|
|
|
int idx = fullData.indexOf(':');
|
|
|
|
|
if (idx < 0) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
String value = fullData.substring(0, idx);
|
|
|
|
|
if (type == 20) {
|
|
|
|
|
value = value.substring(2);
|
2019-05-14 14:08:05 +02:00
|
|
|
|
String[] args = value.split(";");
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (first) {
|
|
|
|
|
value = args[0];
|
|
|
|
|
} else if (args.length > 1) {
|
|
|
|
|
value = args[args.length - 1];
|
|
|
|
|
} else {
|
|
|
|
|
value = "";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
String[] args = value.split(";");
|
2018-07-30 04:07:02 +02:00
|
|
|
|
for (int a = 0; a < args.length; a++) {
|
|
|
|
|
if (args[a].indexOf('=') >= 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
value = args[a];
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getType() {
|
|
|
|
|
if (type == 5) {
|
|
|
|
|
return LocaleController.getString("ContactBirthday", R.string.ContactBirthday);
|
|
|
|
|
} else if (type == 6) {
|
|
|
|
|
if ("ORG".equalsIgnoreCase(getRawType(true))) {
|
|
|
|
|
return LocaleController.getString("ContactJob", R.string.ContactJob);
|
|
|
|
|
} else {
|
|
|
|
|
return LocaleController.getString("ContactJobTitle", R.string.ContactJobTitle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
int idx = fullData.indexOf(':');
|
|
|
|
|
if (idx < 0) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
String value = fullData.substring(0, idx);
|
|
|
|
|
if (type == 20) {
|
|
|
|
|
value = value.substring(2);
|
2019-05-14 14:08:05 +02:00
|
|
|
|
String[] args = value.split(";");
|
2018-07-30 04:07:02 +02:00
|
|
|
|
value = args[0];
|
|
|
|
|
} else {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
String[] args = value.split(";");
|
2018-07-30 04:07:02 +02:00
|
|
|
|
for (int a = 0; a < args.length; a++) {
|
|
|
|
|
if (args[a].indexOf('=') >= 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
value = args[a];
|
|
|
|
|
}
|
|
|
|
|
if (value.startsWith("X-")) {
|
|
|
|
|
value = value.substring(2);
|
|
|
|
|
}
|
2019-05-14 14:08:05 +02:00
|
|
|
|
switch (value) {
|
|
|
|
|
case "PREF":
|
|
|
|
|
value = LocaleController.getString("PhoneMain", R.string.PhoneMain);
|
|
|
|
|
break;
|
|
|
|
|
case "HOME":
|
|
|
|
|
value = LocaleController.getString("PhoneHome", R.string.PhoneHome);
|
|
|
|
|
break;
|
|
|
|
|
case "MOBILE":
|
|
|
|
|
case "CELL":
|
|
|
|
|
value = LocaleController.getString("PhoneMobile", R.string.PhoneMobile);
|
|
|
|
|
break;
|
|
|
|
|
case "OTHER":
|
|
|
|
|
value = LocaleController.getString("PhoneOther", R.string.PhoneOther);
|
|
|
|
|
break;
|
|
|
|
|
case "WORK":
|
|
|
|
|
value = LocaleController.getString("PhoneWork", R.string.PhoneWork);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
value = value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase();
|
2018-07-30 04:07:02 +02:00
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static byte[] getStringBytes(String src) {
|
|
|
|
|
try {
|
|
|
|
|
return src.getBytes("UTF-8");
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return new byte[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ArrayList<TLRPC.User> loadVCardFromStream(Uri uri, int currentAccount, boolean asset, ArrayList<VcardItem> items, String name) {
|
|
|
|
|
ArrayList<TLRPC.User> result = null;
|
|
|
|
|
try {
|
|
|
|
|
InputStream stream;
|
|
|
|
|
if (asset) {
|
|
|
|
|
AssetFileDescriptor fd = ApplicationLoader.applicationContext.getContentResolver().openAssetFileDescriptor(uri, "r");
|
|
|
|
|
stream = fd.createInputStream();
|
|
|
|
|
} else {
|
|
|
|
|
ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver();
|
|
|
|
|
stream = cr.openInputStream(uri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ArrayList<VcardData> vcardDatas = new ArrayList<>();
|
|
|
|
|
VcardData currentData = null;
|
|
|
|
|
|
|
|
|
|
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
|
|
|
|
|
String line;
|
|
|
|
|
String originalLine;
|
|
|
|
|
String pendingLine = null;
|
|
|
|
|
boolean currentIsPhoto = false;
|
|
|
|
|
VcardItem currentItem = null;
|
|
|
|
|
while ((originalLine = line = bufferedReader.readLine()) != null) {
|
|
|
|
|
if (originalLine.startsWith("PHOTO")) {
|
|
|
|
|
currentIsPhoto = true;
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
if (originalLine.indexOf(':') >= 0) {
|
|
|
|
|
currentItem = null;
|
|
|
|
|
currentIsPhoto = false;
|
|
|
|
|
if (originalLine.startsWith("BEGIN:VCARD")) {
|
|
|
|
|
vcardDatas.add(currentData = new VcardData());
|
|
|
|
|
currentData.name = name;
|
|
|
|
|
} else if (originalLine.startsWith("END:VCARD")) {
|
|
|
|
|
|
|
|
|
|
} else if (items != null) {
|
|
|
|
|
if (originalLine.startsWith("TEL")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 0;
|
|
|
|
|
} else if (originalLine.startsWith("EMAIL")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 1;
|
|
|
|
|
} else if (originalLine.startsWith("ADR") || originalLine.startsWith("LABEL") || originalLine.startsWith("GEO")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 2;
|
|
|
|
|
} else if (originalLine.startsWith("URL")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 3;
|
|
|
|
|
} else if (originalLine.startsWith("NOTE")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 4;
|
|
|
|
|
} else if (originalLine.startsWith("BDAY")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 5;
|
|
|
|
|
} else if (originalLine.startsWith("ORG") || originalLine.startsWith("TITLE") || originalLine.startsWith("ROLE")) {
|
|
|
|
|
if (currentItem == null) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 6;
|
|
|
|
|
}
|
|
|
|
|
} else if (originalLine.startsWith("X-ANDROID")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = -1;
|
|
|
|
|
} else if (originalLine.startsWith("X-PHONETIC")) {
|
|
|
|
|
currentItem = null;
|
|
|
|
|
} else if (originalLine.startsWith("X-")) {
|
|
|
|
|
currentItem = new VcardItem();
|
|
|
|
|
currentItem.type = 20;
|
|
|
|
|
}
|
|
|
|
|
if (currentItem != null && currentItem.type >= 0) {
|
|
|
|
|
items.add(currentItem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!currentIsPhoto && currentData != null) {
|
|
|
|
|
if (currentItem == null) {
|
|
|
|
|
if (currentData.vcard.length() > 0) {
|
|
|
|
|
currentData.vcard.append('\n');
|
|
|
|
|
}
|
|
|
|
|
currentData.vcard.append(originalLine);
|
|
|
|
|
} else {
|
|
|
|
|
currentItem.vcardData.add(originalLine);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (pendingLine != null) {
|
|
|
|
|
pendingLine += line;
|
|
|
|
|
line = pendingLine;
|
|
|
|
|
pendingLine = null;
|
|
|
|
|
}
|
|
|
|
|
if (line.contains("=QUOTED-PRINTABLE") && line.endsWith("=")) {
|
|
|
|
|
pendingLine = line.substring(0, line.length() - 1);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (!currentIsPhoto && currentData != null && currentItem != null) {
|
|
|
|
|
currentItem.fullData = line;
|
|
|
|
|
}
|
|
|
|
|
int idx = line.indexOf(":");
|
|
|
|
|
String[] args;
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
|
args = new String[]{
|
|
|
|
|
line.substring(0, idx),
|
2019-05-14 14:08:05 +02:00
|
|
|
|
line.substring(idx + 1).trim()
|
2018-07-30 04:07:02 +02:00
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
args = new String[]{line.trim()};
|
|
|
|
|
}
|
|
|
|
|
if (args.length < 2 || currentData == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-06-25 02:43:10 +02:00
|
|
|
|
if (args[0].startsWith("FN") || args[0].startsWith("N") || args[0].startsWith("ORG") && TextUtils.isEmpty(currentData.name)) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
String nameEncoding = null;
|
|
|
|
|
String nameCharset = null;
|
|
|
|
|
String[] params = args[0].split(";");
|
|
|
|
|
for (String param : params) {
|
|
|
|
|
String[] args2 = param.split("=");
|
|
|
|
|
if (args2.length != 2) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args2[0].equals("CHARSET")) {
|
|
|
|
|
nameCharset = args2[1];
|
|
|
|
|
} else if (args2[0].equals("ENCODING")) {
|
|
|
|
|
nameEncoding = args2[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-25 02:43:10 +02:00
|
|
|
|
if (args[0].startsWith("N")) {
|
|
|
|
|
currentData.name = args[1].replace(';', ' ').trim();
|
|
|
|
|
} else {
|
|
|
|
|
currentData.name = args[1];
|
|
|
|
|
}
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (nameEncoding != null && nameEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
|
|
|
|
|
byte[] bytes = decodeQuotedPrintable(getStringBytes(currentData.name));
|
|
|
|
|
if (bytes != null && bytes.length != 0) {
|
|
|
|
|
String decodedName = new String(bytes, nameCharset);
|
|
|
|
|
if (decodedName != null) {
|
|
|
|
|
currentData.name = decodedName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (args[0].startsWith("TEL")) {
|
|
|
|
|
currentData.phones.add(args[1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
bufferedReader.close();
|
|
|
|
|
stream.close();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
for (int a = 0; a < vcardDatas.size(); a++) {
|
|
|
|
|
VcardData vcardData = vcardDatas.get(a);
|
|
|
|
|
if (vcardData.name != null && !vcardData.phones.isEmpty()) {
|
|
|
|
|
if (result == null) {
|
|
|
|
|
result = new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String phoneToUse = vcardData.phones.get(0);
|
|
|
|
|
for (int b = 0; b < vcardData.phones.size(); b++) {
|
|
|
|
|
String phone = vcardData.phones.get(b);
|
|
|
|
|
String sphone = phone.substring(Math.max(0, phone.length() - 7));
|
|
|
|
|
if (ContactsController.getInstance(currentAccount).contactsByShortPhone.get(sphone) != null) {
|
|
|
|
|
phoneToUse = phone;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TLRPC.User user = new TLRPC.TL_userContact_old2();
|
|
|
|
|
user.phone = phoneToUse;
|
|
|
|
|
user.first_name = vcardData.name;
|
|
|
|
|
user.last_name = "";
|
|
|
|
|
user.id = 0;
|
2019-09-10 12:56:11 +02:00
|
|
|
|
TLRPC.TL_restrictionReason reason = new TLRPC.TL_restrictionReason();
|
|
|
|
|
reason.text = vcardData.vcard.toString();
|
|
|
|
|
reason.platform = "";
|
|
|
|
|
reason.reason = "";
|
|
|
|
|
user.restriction_reason.add(reason);
|
2018-07-30 04:07:02 +02:00
|
|
|
|
result.add(user);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-03 00:39:05 +02:00
|
|
|
|
public static Typeface getTypeface(String assetPath) {
|
|
|
|
|
synchronized (typefaceCache) {
|
|
|
|
|
if (!typefaceCache.containsKey(assetPath)) {
|
|
|
|
|
try {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
Typeface t;
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 26) {
|
|
|
|
|
Typeface.Builder builder = new Typeface.Builder(ApplicationLoader.applicationContext.getAssets(), assetPath);
|
|
|
|
|
if (assetPath.contains("medium")) {
|
|
|
|
|
builder.setWeight(700);
|
|
|
|
|
}
|
|
|
|
|
if (assetPath.contains("italic")) {
|
|
|
|
|
builder.setItalic(true);
|
|
|
|
|
}
|
|
|
|
|
t = builder.build();
|
|
|
|
|
} else {
|
|
|
|
|
t = Typeface.createFromAsset(ApplicationLoader.applicationContext.getAssets(), assetPath);
|
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
|
typefaceCache.put(assetPath, t);
|
|
|
|
|
} catch (Exception e) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (BuildVars.LOGS_ENABLED) {
|
|
|
|
|
FileLog.e("Could not get typeface '" + assetPath + "' because " + e.getMessage());
|
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
|
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;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
try {
|
|
|
|
|
if (waitingForSms) {
|
|
|
|
|
SmsRetrieverClient client = SmsRetriever.getClient(ApplicationLoader.applicationContext);
|
|
|
|
|
Task<Void> task = client.startSmsRetriever();
|
|
|
|
|
task.addOnSuccessListener(aVoid -> {
|
|
|
|
|
if (BuildVars.DEBUG_VERSION) {
|
|
|
|
|
FileLog.d("sms listener registered");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
public static int getShadowHeight() {
|
|
|
|
|
if (density >= 4.0f) {
|
|
|
|
|
return 3;
|
|
|
|
|
} else if (density >= 2.0f) {
|
|
|
|
|
return 2;
|
|
|
|
|
} else {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-16 13:26:32 +01:00
|
|
|
|
public static boolean isWaitingForCall() {
|
|
|
|
|
boolean value;
|
|
|
|
|
synchronized (callLock) {
|
|
|
|
|
value = waitingForCall;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-27 10:33:11 +02:00
|
|
|
|
private static CallReceiver callReceiver;
|
|
|
|
|
|
2016-03-16 13:26:32 +01:00
|
|
|
|
public static void setWaitingForCall(boolean value) {
|
|
|
|
|
synchronized (callLock) {
|
2018-08-27 10:33:11 +02:00
|
|
|
|
try {
|
|
|
|
|
if (value) {
|
|
|
|
|
if (callReceiver == null) {
|
|
|
|
|
final IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
|
|
|
|
|
ApplicationLoader.applicationContext.registerReceiver(callReceiver = new CallReceiver(), filter);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (callReceiver != null) {
|
|
|
|
|
ApplicationLoader.applicationContext.unregisterReceiver(callReceiver);
|
|
|
|
|
callReceiver = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
2016-03-16 13:26:32 +01:00
|
|
|
|
waitingForCall = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static boolean showKeyboard(View view) {
|
2014-07-03 00:39:05 +02:00
|
|
|
|
if (view == null) {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
return false;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|
2016-05-25 23:49:47 +02:00
|
|
|
|
try {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
2019-01-23 18:03:33 +01:00
|
|
|
|
return inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
|
2016-05-25 23:49:47 +02:00
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2016-05-25 23:49:47 +02:00
|
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
|
return false;
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
public static String[] getCurrentKeyboardLanguage() {
|
|
|
|
|
try {
|
|
|
|
|
InputMethodManager inputManager = (InputMethodManager) ApplicationLoader.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
|
InputMethodSubtype inputMethodSubtype = inputManager.getCurrentInputMethodSubtype();
|
|
|
|
|
String locale = null;
|
|
|
|
|
if (inputMethodSubtype != null) {
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 24) {
|
|
|
|
|
locale = inputMethodSubtype.getLanguageTag();
|
|
|
|
|
}
|
|
|
|
|
if (TextUtils.isEmpty(locale)) {
|
|
|
|
|
locale = inputMethodSubtype.getLocale();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
inputMethodSubtype = inputManager.getLastInputMethodSubtype();
|
|
|
|
|
if (inputMethodSubtype != null) {
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 24) {
|
|
|
|
|
locale = inputMethodSubtype.getLanguageTag();
|
|
|
|
|
}
|
|
|
|
|
if (TextUtils.isEmpty(locale)) {
|
|
|
|
|
locale = inputMethodSubtype.getLocale();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (TextUtils.isEmpty(locale)) {
|
|
|
|
|
locale = LocaleController.getSystemLocaleStringIso639();
|
|
|
|
|
String locale2;
|
|
|
|
|
LocaleController.LocaleInfo localeInfo = LocaleController.getInstance().getCurrentLocaleInfo();
|
|
|
|
|
locale2 = localeInfo.getBaseLangCode();
|
|
|
|
|
if (TextUtils.isEmpty(locale2)) {
|
|
|
|
|
locale2 = localeInfo.getLangCode();
|
|
|
|
|
}
|
|
|
|
|
if (locale.contains(locale2) || locale2.contains(locale)) {
|
|
|
|
|
if (!locale.contains("en")) {
|
|
|
|
|
locale2 = "en";
|
|
|
|
|
} else {
|
|
|
|
|
locale2 = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!TextUtils.isEmpty(locale2)) {
|
|
|
|
|
return new String[]{locale.replace('_', '-'), locale2};
|
|
|
|
|
} else {
|
|
|
|
|
return new String[]{locale.replace('_', '-')};
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return new String[]{locale.replace('_', '-')};
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return new String[]{"en"};
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
2021-03-19 11:25:58 +01:00
|
|
|
|
|
2016-05-25 23:49:47 +02:00
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 08:48:30 +01:00
|
|
|
|
public static ArrayList<File> getDataDirs() {
|
|
|
|
|
ArrayList<File> result = null;
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 19) {
|
|
|
|
|
File[] dirs = ApplicationLoader.applicationContext.getExternalFilesDirs(null);
|
|
|
|
|
if (dirs != null) {
|
|
|
|
|
for (int a = 0; a < dirs.length; a++) {
|
|
|
|
|
if (dirs[a] == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
String path = dirs[a].getAbsolutePath();
|
|
|
|
|
|
|
|
|
|
if (result == null) {
|
|
|
|
|
result = new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
result.add(dirs[a]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (result == null) {
|
|
|
|
|
result = new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
if (result.isEmpty()) {
|
|
|
|
|
result.add(Environment.getExternalStorageDirectory());
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static ArrayList<File> getRootDirs() {
|
|
|
|
|
ArrayList<File> result = null;
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 19) {
|
|
|
|
|
File[] dirs = ApplicationLoader.applicationContext.getExternalFilesDirs(null);
|
|
|
|
|
if (dirs != null) {
|
|
|
|
|
for (int a = 0; a < dirs.length; a++) {
|
|
|
|
|
if (dirs[a] == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
String path = dirs[a].getAbsolutePath();
|
|
|
|
|
int idx = path.indexOf("/Android");
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
|
if (result == null) {
|
|
|
|
|
result = new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
result.add(new File(path.substring(0, idx)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (result == null) {
|
|
|
|
|
result = new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
if (result.isEmpty()) {
|
|
|
|
|
result.add(Environment.getExternalStorageDirectory());
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-01-02 23:15:07 +01:00
|
|
|
|
}
|
|
|
|
|
if (state == null || state.startsWith(Environment.MEDIA_MOUNTED)) {
|
2014-07-20 01:31:49 +02:00
|
|
|
|
try {
|
2020-12-23 08:48:30 +01:00
|
|
|
|
File file;
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 19) {
|
|
|
|
|
File[] dirs = ApplicationLoader.applicationContext.getExternalCacheDirs();
|
|
|
|
|
file = dirs[0];
|
|
|
|
|
if (!TextUtils.isEmpty(SharedConfig.storageCacheDir)) {
|
|
|
|
|
for (int a = 0; a < dirs.length; a++) {
|
|
|
|
|
if (dirs[a] != null && dirs[a].getAbsolutePath().startsWith(SharedConfig.storageCacheDir)) {
|
|
|
|
|
file = dirs[a];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
file = ApplicationLoader.applicationContext.getExternalCacheDir();
|
|
|
|
|
}
|
2014-07-20 01:31:49 +02:00
|
|
|
|
if (file != null) {
|
|
|
|
|
return file;
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(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
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
public static int dpr(float value) {
|
|
|
|
|
if (value == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return Math.round(density * value);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
|
public static int dp2(float value) {
|
|
|
|
|
if (value == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return (int) Math.floor(density * value);
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
|
public static int compare(long lhs, long 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 {
|
2020-01-03 16:45:22 +01:00
|
|
|
|
float oldDensity = density;
|
2016-10-11 13:57:01 +02:00
|
|
|
|
density = context.getResources().getDisplayMetrics().density;
|
2020-01-03 16:45:22 +01:00
|
|
|
|
float newDensity = density;
|
|
|
|
|
if (firstConfigurationWas && Math.abs(oldDensity - newDensity) > 0.001) {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
Theme.reloadAllResources(context);
|
|
|
|
|
}
|
|
|
|
|
firstConfigurationWas = true;
|
2016-10-11 13:57:01 +02:00
|
|
|
|
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);
|
2019-12-31 14:08:08 +01:00
|
|
|
|
screenRefreshRate = display.getRefreshRate();
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-08 18:32:04 +02:00
|
|
|
|
if (roundMessageSize == 0) {
|
|
|
|
|
if (AndroidUtilities.isTablet()) {
|
|
|
|
|
roundMessageSize = (int) (AndroidUtilities.getMinTabletSide() * 0.6f);
|
2021-07-30 16:49:55 +02:00
|
|
|
|
roundPlayingMessageSize = (int) (AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(28));
|
2017-07-08 18:32:04 +02:00
|
|
|
|
} else {
|
|
|
|
|
roundMessageSize = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.6f);
|
2021-07-30 16:49:55 +02:00
|
|
|
|
roundPlayingMessageSize = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(28));
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
2019-12-31 14:08:08 +01:00
|
|
|
|
roundMessageInset = dp(2);
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (BuildVars.LOGS_ENABLED) {
|
2022-03-11 17:49:54 +01:00
|
|
|
|
if (statusBarHeight == 0) {
|
|
|
|
|
fillStatusBarHeight(context);
|
|
|
|
|
}
|
|
|
|
|
FileLog.e("density = " + density + " display size = " + displaySize.x + " " + displaySize.y + " " + displayMetrics.xdpi + "x" + displayMetrics.ydpi + ", screen layout: " + configuration.screenLayout + ", statusbar height: " + statusBarHeight + ", navbar height: " + navigationBarHeight);
|
2018-07-30 04:07:02 +02:00
|
|
|
|
}
|
2022-06-21 04:51:00 +02:00
|
|
|
|
ViewConfiguration vc = ViewConfiguration.get(context);
|
|
|
|
|
touchSlop = vc.getScaledTouchSlop();
|
2014-07-03 00:39:05 +02:00
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-27 12:53:00 +02:00
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
|
public static double fixLocationCoord(double value) {
|
|
|
|
|
return ((long) (value * 1000000)) / 1000000.0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static String formapMapUrl(int account, double lat, double lon, int width, int height, boolean marker, int zoom, int provider) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
int scale = Math.min(2, (int) Math.ceil(AndroidUtilities.density));
|
2019-12-31 14:08:08 +01:00
|
|
|
|
if (provider == -1) {
|
|
|
|
|
provider = MessagesController.getInstance(account).mapProvider;
|
|
|
|
|
}
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (provider == 1 || provider == 3) {
|
|
|
|
|
String lang = null;
|
|
|
|
|
String[] availableLangs = new String[]{"ru_RU", "tr_TR"};
|
|
|
|
|
LocaleController.LocaleInfo localeInfo = LocaleController.getInstance().getCurrentLocaleInfo();
|
|
|
|
|
for (int a = 0; a < availableLangs.length; a++) {
|
|
|
|
|
if (availableLangs[a].toLowerCase().contains(localeInfo.shortName)) {
|
|
|
|
|
lang = availableLangs[a];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (lang == null) {
|
|
|
|
|
lang = "en_US";
|
|
|
|
|
}
|
|
|
|
|
if (marker) {
|
|
|
|
|
return String.format(Locale.US, "https://static-maps.yandex.ru/1.x/?ll=%.6f,%.6f&z=%d&size=%d,%d&l=map&scale=%d&pt=%.6f,%.6f,vkbkm&lang=%s", lon, lat, zoom, width * scale, height * scale, scale, lon, lat, lang);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "https://static-maps.yandex.ru/1.x/?ll=%.6f,%.6f&z=%d&size=%d,%d&l=map&scale=%d&lang=%s", lon, lat, zoom, width * scale, height * scale, scale, lang);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
String k = MessagesController.getInstance(account).mapKey;
|
|
|
|
|
if (!TextUtils.isEmpty(k)) {
|
|
|
|
|
if (marker) {
|
|
|
|
|
return String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&maptype=roadmap&scale=%d&markers=color:red%%7Csize:mid%%7C%.6f,%.6f&sensor=false&key=%s", lat, lon, zoom, width, height, scale, lat, lon, k);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&maptype=roadmap&scale=%d&key=%s", lat, lon, zoom, width, height, scale, k);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (marker) {
|
|
|
|
|
return String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&maptype=roadmap&scale=%d&markers=color:red%%7Csize:mid%%7C%.6f,%.6f&sensor=false", lat, lon, zoom, width, height, scale, lat, lon);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%.6f,%.6f&zoom=%d&size=%dx%d&maptype=roadmap&scale=%d", lat, lon, zoom, width, height, scale);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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-10-14 10:13:16 +02:00
|
|
|
|
public static int getMyLayerVersion(int layer) {
|
|
|
|
|
return layer & 0xffff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getPeerLayerVersion(int layer) {
|
2021-06-25 02:43:10 +02:00
|
|
|
|
return Math.max(73, (layer >> 16) & 0xffff);
|
2014-10-14 10:13:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) {
|
2021-07-19 17:56:43 +02:00
|
|
|
|
if (ApplicationLoader.applicationHandler == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
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) {
|
2021-07-19 17:56:43 +02:00
|
|
|
|
if (ApplicationLoader.applicationHandler == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-10-09 17:55:05 +02:00
|
|
|
|
ApplicationLoader.applicationHandler.removeCallbacks(runnable);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-25 02:43:10 +02:00
|
|
|
|
public static boolean isValidWallChar(char ch) {
|
|
|
|
|
return ch == '-' || ch == '~';
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-24 04:17:27 +02:00
|
|
|
|
public static boolean isTablet() {
|
2014-09-24 17:08:25 +02:00
|
|
|
|
if (isTablet == null) {
|
2021-07-31 01:39:13 +02:00
|
|
|
|
isTablet = ApplicationLoader.applicationContext != null && ApplicationLoader.applicationContext.getResources().getBoolean(R.bool.isTablet);
|
2014-09-24 17:08:25 +02:00
|
|
|
|
}
|
|
|
|
|
return isTablet;
|
2014-09-24 04:17:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static boolean isSmallScreen() {
|
|
|
|
|
if (isSmallScreen == null) {
|
2022-03-13 02:58:00 +01:00
|
|
|
|
isSmallScreen = (Math.max(displaySize.x, displaySize.y) - statusBarHeight - navigationBarHeight) / density <= 650;
|
2022-03-11 17:49:54 +01:00
|
|
|
|
}
|
|
|
|
|
return isSmallScreen;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
2021-06-25 02:43:10 +02:00
|
|
|
|
return minSide <= 690;
|
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) {
|
2017-07-23 14:56:38 +02:00
|
|
|
|
photoSize = 1280;
|
2014-09-30 00:48:11 +02:00
|
|
|
|
}
|
|
|
|
|
return photoSize;
|
|
|
|
|
}
|
2014-10-14 22:36:15 +02:00
|
|
|
|
|
2017-12-08 18:35:59 +01: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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-10-21 22:35:16 +02:00
|
|
|
|
}
|
2017-12-08 18:35:59 +01:00
|
|
|
|
}*/
|
2014-11-06 22:34:47 +01:00
|
|
|
|
|
2019-08-22 01:53:26 +02:00
|
|
|
|
private static Runnable unregisterRunnable;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
private static boolean hasCallPermissions = Build.VERSION.SDK_INT >= 23;
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
public static void endIncomingCall() {
|
|
|
|
|
if (!hasCallPermissions) {
|
2015-02-26 02:32:51 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
|
|
|
|
|
Class c = Class.forName(tm.getClass().getName());
|
|
|
|
|
Method m = c.getDeclaredMethod("getITelephony");
|
|
|
|
|
m.setAccessible(true);
|
|
|
|
|
ITelephony telephonyService = (ITelephony) m.invoke(tm);
|
|
|
|
|
telephonyService = (ITelephony) m.invoke(tm);
|
|
|
|
|
telephonyService.silenceRinger();
|
|
|
|
|
telephonyService.endCall();
|
2019-08-22 01:53:26 +02:00
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String obtainLoginPhoneCall(String pattern) {
|
|
|
|
|
if (!hasCallPermissions) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
try (Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(
|
|
|
|
|
CallLog.Calls.CONTENT_URI,
|
|
|
|
|
new String[]{CallLog.Calls.NUMBER, CallLog.Calls.DATE},
|
|
|
|
|
CallLog.Calls.TYPE + " IN (" + CallLog.Calls.MISSED_TYPE + "," + CallLog.Calls.INCOMING_TYPE + "," + CallLog.Calls.REJECTED_TYPE + ")",
|
|
|
|
|
null,
|
|
|
|
|
"date DESC LIMIT 5")) {
|
|
|
|
|
while (cursor.moveToNext()) {
|
|
|
|
|
String number = cursor.getString(0);
|
|
|
|
|
long date = cursor.getLong(1);
|
|
|
|
|
if (BuildVars.LOGS_ENABLED) {
|
|
|
|
|
FileLog.e("number = " + number);
|
|
|
|
|
}
|
|
|
|
|
if (Math.abs(System.currentTimeMillis() - date) >= 60 * 60 * 1000) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (checkPhonePattern(pattern, number)) {
|
|
|
|
|
return number;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-26 02:32:51 +01:00
|
|
|
|
} catch (Exception e) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
FileLog.e(e);
|
2015-02-26 02:32:51 +01:00
|
|
|
|
}
|
2019-08-22 01:53:26 +02:00
|
|
|
|
return null;
|
2015-02-26 02:32:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
|
public static boolean checkPhonePattern(String pattern, String phone) {
|
|
|
|
|
if (TextUtils.isEmpty(pattern) || pattern.equals("*")) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-05-14 14:08:05 +02:00
|
|
|
|
String[] args = pattern.split("\\*");
|
2017-03-31 01:58:05 +02:00
|
|
|
|
phone = PhoneFormat.stripExceptNumbers(phone);
|
|
|
|
|
int checkStart = 0;
|
|
|
|
|
int index;
|
|
|
|
|
for (int a = 0; a < args.length; a++) {
|
|
|
|
|
String arg = args[a];
|
|
|
|
|
if (!TextUtils.isEmpty(arg)) {
|
|
|
|
|
if ((index = phone.indexOf(arg, checkStart)) == -1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
checkStart = index + arg.length();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 13:57:01 +02:00
|
|
|
|
private static Field mAttachInfoField;
|
|
|
|
|
private static Field mStableInsetsField;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
|
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 {
|
2020-12-23 08:48:30 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= 23) {
|
|
|
|
|
WindowInsets insets = view.getRootWindowInsets();
|
|
|
|
|
return insets != null ? insets.getStableInsetBottom() : 0;
|
|
|
|
|
} else {
|
|
|
|
|
if (mAttachInfoField == null) {
|
|
|
|
|
mAttachInfoField = View.class.getDeclaredField("mAttachInfo");
|
|
|
|
|
mAttachInfoField.setAccessible(true);
|
|
|
|
|
}
|
|
|
|
|
Object mAttachInfo = mAttachInfoField.get(view);
|
|
|
|
|
if (mAttachInfo != null) {
|
|
|
|
|
if (mStableInsetsField == null) {
|
|
|
|
|
mStableInsetsField = mAttachInfo.getClass().getDeclaredField("mStableInsets");
|
|
|
|
|
mStableInsetsField.setAccessible(true);
|
|
|
|
|
}
|
|
|
|
|
Rect insets = (Rect) mStableInsetsField.get(mAttachInfo);
|
|
|
|
|
return insets.bottom;
|
2016-10-11 13:57:01 +02:00
|
|
|
|
}
|
2014-11-06 22:34:47 +01:00
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-11-06 22:34:47 +01:00
|
|
|
|
}
|
|
|
|
|
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());
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-11-07 11:23:17 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2014-11-07 11:23:17 +01:00
|
|
|
|
}
|
|
|
|
|
return size;
|
|
|
|
|
}
|
2014-11-11 23:16:17 +01:00
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
|
public static void setEnabled(View view, boolean enabled) {
|
|
|
|
|
if (view == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
view.setEnabled(enabled);
|
|
|
|
|
if (view instanceof ViewGroup) {
|
|
|
|
|
ViewGroup viewGroup = (ViewGroup) view;
|
|
|
|
|
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
|
|
|
|
setEnabled(viewGroup.getChildAt(i), enabled);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 11:52:40 +01:00
|
|
|
|
public static int charSequenceIndexOf(CharSequence cs, CharSequence needle, int fromIndex) {
|
|
|
|
|
for (int i = fromIndex; i < cs.length() - needle.length(); i++) {
|
|
|
|
|
boolean eq = true;
|
|
|
|
|
for (int j = 0; j < needle.length(); j++) {
|
|
|
|
|
if (needle.charAt(j) != cs.charAt(i + j)) {
|
|
|
|
|
eq = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (eq)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int charSequenceIndexOf(CharSequence cs, CharSequence needle) {
|
|
|
|
|
return charSequenceIndexOf(cs, needle, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean charSequenceContains(CharSequence cs, CharSequence needle) {
|
|
|
|
|
return charSequenceIndexOf(cs, needle) != -1;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
|
public static void setViewPagerEdgeEffectColor(ViewPager viewPager, int color) {
|
2014-11-11 23:16:17 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= 21) {
|
|
|
|
|
try {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
Field field = ViewPager.class.getDeclaredField("mLeftEdge");
|
2019-05-14 14:08:05 +02:00
|
|
|
|
field.setAccessible(true);
|
|
|
|
|
EdgeEffect mLeftEdge = (EdgeEffect) field.get(viewPager);
|
2017-03-31 01:58:05 +02:00
|
|
|
|
if (mLeftEdge != null) {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
mLeftEdge.setColor(color);
|
2017-03-31 01:58:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
field = ViewPager.class.getDeclaredField("mRightEdge");
|
|
|
|
|
field.setAccessible(true);
|
2019-05-14 14:08:05 +02:00
|
|
|
|
EdgeEffect mRightEdge = (EdgeEffect) field.get(viewPager);
|
2017-03-31 01:58:05 +02:00
|
|
|
|
if (mRightEdge != null) {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
mRightEdge.setColor(color);
|
2017-03-31 01:58:05 +02:00
|
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setScrollViewEdgeEffectColor(HorizontalScrollView scrollView, int color) {
|
2020-12-23 08:48:30 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
|
|
|
scrollView.setEdgeEffectColor(color);
|
|
|
|
|
} else if (Build.VERSION.SDK_INT >= 21) {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
try {
|
|
|
|
|
Field field = HorizontalScrollView.class.getDeclaredField("mEdgeGlowLeft");
|
|
|
|
|
field.setAccessible(true);
|
|
|
|
|
EdgeEffect mEdgeGlowTop = (EdgeEffect) field.get(scrollView);
|
|
|
|
|
if (mEdgeGlowTop != null) {
|
|
|
|
|
mEdgeGlowTop.setColor(color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
field = HorizontalScrollView.class.getDeclaredField("mEdgeGlowRight");
|
|
|
|
|
field.setAccessible(true);
|
|
|
|
|
EdgeEffect mEdgeGlowBottom = (EdgeEffect) field.get(scrollView);
|
|
|
|
|
if (mEdgeGlowBottom != null) {
|
|
|
|
|
mEdgeGlowBottom.setColor(color);
|
|
|
|
|
}
|
2017-03-31 01:58:05 +02:00
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setScrollViewEdgeEffectColor(ScrollView scrollView, int color) {
|
2020-12-23 08:48:30 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= 29) {
|
|
|
|
|
scrollView.setTopEdgeEffectColor(color);
|
|
|
|
|
scrollView.setBottomEdgeEffectColor(color);
|
|
|
|
|
} else if (Build.VERSION.SDK_INT >= 21) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
try {
|
|
|
|
|
Field field = ScrollView.class.getDeclaredField("mEdgeGlowTop");
|
|
|
|
|
field.setAccessible(true);
|
|
|
|
|
EdgeEffect mEdgeGlowTop = (EdgeEffect) field.get(scrollView);
|
2014-11-11 23:16:17 +01:00
|
|
|
|
if (mEdgeGlowTop != null) {
|
|
|
|
|
mEdgeGlowTop.setColor(color);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
|
field = ScrollView.class.getDeclaredField("mEdgeGlowBottom");
|
2014-11-11 23:16:17 +01:00
|
|
|
|
field.setAccessible(true);
|
2017-03-31 01:58:05 +02:00
|
|
|
|
EdgeEffect mEdgeGlowBottom = (EdgeEffect) field.get(scrollView);
|
2014-11-11 23:16:17 +01:00
|
|
|
|
if (mEdgeGlowBottom != null) {
|
|
|
|
|
mEdgeGlowBottom.setColor(color);
|
|
|
|
|
}
|
2020-12-23 08:48:30 +01:00
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
2014-11-11 23:16:17 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
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;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
public static final int FLAG_TAG_URL = 8;
|
|
|
|
|
public static final int FLAG_TAG_ALL = FLAG_TAG_BR | FLAG_TAG_BOLD | FLAG_TAG_URL;
|
2015-06-29 19:12:11 +02:00
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
|
public static SpannableStringBuilder replaceTags(String str, int flag, Object... args) {
|
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
|
|
|
|
}
|
2017-12-08 18:35:59 +01:00
|
|
|
|
while ((start = stringBuilder.indexOf("**")) != -1) {
|
|
|
|
|
stringBuilder.replace(start, start + 2, "");
|
|
|
|
|
end = stringBuilder.indexOf("**");
|
|
|
|
|
if (end >= 0) {
|
|
|
|
|
stringBuilder.replace(end, end + 2, "");
|
|
|
|
|
bolds.add(start);
|
|
|
|
|
bolds.add(end);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-29 19:12:11 +02:00
|
|
|
|
}
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if ((flag & FLAG_TAG_URL) != 0) {
|
|
|
|
|
while ((start = stringBuilder.indexOf("**")) != -1) {
|
|
|
|
|
stringBuilder.replace(start, start + 2, "");
|
|
|
|
|
end = stringBuilder.indexOf("**");
|
|
|
|
|
if (end >= 0) {
|
|
|
|
|
stringBuilder.replace(end, end + 2, "");
|
|
|
|
|
bolds.add(start);
|
|
|
|
|
bolds.add(end);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-04-09 20:00:14 +02:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
return spannableStringBuilder;
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(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
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
|
public static class LinkMovementMethodMy extends LinkMovementMethod {
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
|
|
|
|
|
try {
|
|
|
|
|
boolean result = super.onTouchEvent(widget, buffer, event);
|
|
|
|
|
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
|
|
|
|
|
Selection.removeSelection(buffer);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-23 07:15:40 +01:00
|
|
|
|
public static boolean needShowPasscode() {
|
|
|
|
|
return needShowPasscode(false);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
}
|
2020-01-23 07:15:40 +01:00
|
|
|
|
int uptime = (int) (SystemClock.elapsedRealtime() / 1000);
|
|
|
|
|
if (BuildVars.LOGS_ENABLED && reset && SharedConfig.passcodeHash.length() > 0) {
|
|
|
|
|
FileLog.d("wasInBackground = " + wasInBackground + " appLocked = " + SharedConfig.appLocked + " autoLockIn = " + SharedConfig.autoLockIn + " lastPauseTime = " + SharedConfig.lastPauseTime + " uptime = " + uptime);
|
|
|
|
|
}
|
2018-07-30 04:07:02 +02:00
|
|
|
|
return SharedConfig.passcodeHash.length() > 0 && wasInBackground &&
|
2020-01-23 07:15:40 +01:00
|
|
|
|
(SharedConfig.appLocked ||
|
|
|
|
|
SharedConfig.autoLockIn != 0 && SharedConfig.lastPauseTime != 0 && !SharedConfig.appLocked && (SharedConfig.lastPauseTime + SharedConfig.autoLockIn) <= uptime ||
|
|
|
|
|
uptime + 5 < SharedConfig.lastPauseTime);
|
2015-02-26 02:32:51 +01:00
|
|
|
|
}
|
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) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (view == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
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();
|
2020-06-04 18:47:15 +02:00
|
|
|
|
animatorSet.playTogether(ObjectAnimator.ofFloat(view, "translationX", dp(x)));
|
2016-06-24 12:27:15 +02:00
|
|
|
|
animatorSet.setDuration(50);
|
2017-03-31 01:58:05 +02:00
|
|
|
|
animatorSet.addListener(new AnimatorListenerAdapter() {
|
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
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static void shakeViewSpring(View view) {
|
|
|
|
|
shakeViewSpring(view, 10, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void shakeViewSpring(View view, float shiftDp) {
|
|
|
|
|
shakeViewSpring(view, shiftDp, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void shakeViewSpring(View view, Runnable endCallback) {
|
|
|
|
|
shakeViewSpring(view, 10, endCallback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void shakeViewSpring(View view, float shiftDp, Runnable endCallback) {
|
|
|
|
|
int shift = dp(shiftDp);
|
|
|
|
|
new SpringAnimation(view, DynamicAnimation.TRANSLATION_X, 0)
|
|
|
|
|
.setSpring(new SpringForce(0).setStiffness(600f))
|
|
|
|
|
.setStartVelocity(-shift * 100)
|
|
|
|
|
.addEndListener((animation, canceled, value, velocity) -> {
|
|
|
|
|
if (endCallback != null) endCallback.run();
|
|
|
|
|
})
|
|
|
|
|
.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
|
|
|
|
|
2020-03-30 14:00:09 +02:00
|
|
|
|
public static void startAppCenter(Activity context) {
|
2021-09-21 11:51:08 +02:00
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-30 14:00:09 +02:00
|
|
|
|
private static long lastUpdateCheckTime;
|
|
|
|
|
public static void checkForUpdates() {
|
2021-09-21 11:51:08 +02:00
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 14:02:02 +01:00
|
|
|
|
public static void appCenterLog(Throwable e) {
|
2022-06-28 12:00:33 +02:00
|
|
|
|
|
2021-12-07 14:02:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static boolean shouldShowClipboardToast() {
|
2022-04-16 16:43:17 +02:00
|
|
|
|
return Build.VERSION.SDK_INT < Build.VERSION_CODES.S || !OneUIUtilities.hasBuiltInClipboardToasts();
|
2022-03-11 17:49:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2016-05-25 23:49:47 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
|
public static void addMediaToGallery(String fromPath) {
|
|
|
|
|
if (fromPath == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
File f = new File(fromPath);
|
2021-11-09 02:49:31 +01:00
|
|
|
|
addMediaToGallery(f);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-09 02:49:31 +01:00
|
|
|
|
public static void addMediaToGallery(File file) {
|
|
|
|
|
Uri uri = Uri.fromFile(file);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-10-29 18:10:07 +01:00
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-05 11:06:49 +01:00
|
|
|
|
private static File getAlbumDir(boolean secretChat) {
|
2021-11-09 02:49:31 +01:00
|
|
|
|
if (secretChat || !BuildVars.NO_SCOPED_STORAGE ||(Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
|
|
|
|
|
return FileLoader.getDirectory(FileLoader.MEDIA_DIR_IMAGE);
|
2015-10-29 18:10:07 +01:00
|
|
|
|
}
|
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()) {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
if (!storageDir.exists()) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (BuildVars.LOGS_ENABLED) {
|
|
|
|
|
FileLog.d("failed to create directory");
|
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (BuildVars.LOGS_ENABLED) {
|
|
|
|
|
FileLog.d("External storage is not mounted READ/WRITE.");
|
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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=?";
|
2019-01-23 18:03:33 +01:00
|
|
|
|
final String[] selectionArgs = new String[]{
|
2015-05-21 23:27:27 +02:00
|
|
|
|
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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
|
|
|
|
|
|
|
|
|
|
final String column = "_data";
|
|
|
|
|
final String[] projection = {
|
|
|
|
|
column
|
|
|
|
|
};
|
2019-05-14 14:08:05 +02:00
|
|
|
|
try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) {
|
2015-05-21 23:27:27 +02:00
|
|
|
|
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
|
|
|
|
}
|
2017-12-08 18:35:59 +01:00
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
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() {
|
2019-12-31 14:08:08 +01:00
|
|
|
|
return generatePicturePath(false, null);
|
2019-01-23 18:03:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static File generatePicturePath(boolean secretChat, String ext) {
|
2015-05-21 23:27:27 +02:00
|
|
|
|
try {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
File publicDir = FileLoader.getDirectory(FileLoader.MEDIA_DIR_IMAGE_PUBLIC);
|
|
|
|
|
if (secretChat || publicDir == null) {
|
|
|
|
|
File storageDir = ApplicationLoader.applicationContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
|
|
|
|
return new File(storageDir, generateFileName(0, ext));
|
|
|
|
|
} else {
|
|
|
|
|
return new File(publicDir, generateFileName(0, ext));
|
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-09 02:49:31 +01:00
|
|
|
|
public static String generateFileName(int type, String ext) {
|
|
|
|
|
Date date = new Date();
|
|
|
|
|
date.setTime(System.currentTimeMillis() + Utilities.random.nextInt(1000) + 1);
|
|
|
|
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.US).format(date);
|
|
|
|
|
if (type == 0) {
|
|
|
|
|
return "IMG_" + timeStamp + "." + (TextUtils.isEmpty(ext) ? "jpg" : ext);
|
|
|
|
|
} else {
|
|
|
|
|
return "VID_" + timeStamp + ".mp4";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
|
public static CharSequence generateSearchName(String name, String name2, String q) {
|
2020-10-15 02:39:36 +02:00
|
|
|
|
if (name == null && name2 == null || TextUtils.isEmpty(q)) {
|
2015-05-21 23:27:27 +02:00
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-31 01:58:05 +02:00
|
|
|
|
String query = wholeString.substring(idx, Math.min(wholeString.length(), end));
|
2015-05-21 23:27:27 +02:00
|
|
|
|
if (query.startsWith(" ")) {
|
|
|
|
|
builder.append(" ");
|
|
|
|
|
}
|
|
|
|
|
query = query.trim();
|
2017-03-31 01:58:05 +02:00
|
|
|
|
|
|
|
|
|
int start = builder.length();
|
|
|
|
|
builder.append(query);
|
2020-10-15 02:39:36 +02:00
|
|
|
|
builder.setSpan(new ForegroundColorSpanThemable(Theme.key_windowBackgroundWhiteBlueText4), start, start + query.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
|
|
|
|
|
lastIndex = end;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-08 18:35:59 +01:00
|
|
|
|
if (lastIndex != -1 && lastIndex < wholeString.length()) {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
builder.append(wholeString.substring(lastIndex));
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return builder;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static boolean isKeyguardSecure() {
|
|
|
|
|
KeyguardManager km = (KeyguardManager) ApplicationLoader.applicationContext.getSystemService(Context.KEYGUARD_SERVICE);
|
|
|
|
|
return km.isKeyguardSecure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean isSimAvailable() {
|
|
|
|
|
TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE);
|
|
|
|
|
int state = tm.getSimState();
|
|
|
|
|
return state != TelephonyManager.SIM_STATE_ABSENT && state != TelephonyManager.SIM_STATE_UNKNOWN && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE && !isAirplaneModeOn();
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static boolean isAirplaneModeOn() {
|
|
|
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
|
|
|
|
return Settings.System.getInt(ApplicationLoader.applicationContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
|
|
|
|
|
} else {
|
|
|
|
|
return Settings.Global.getInt(ApplicationLoader.applicationContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
|
public static File generateVideoPath() {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
return generateVideoPath(false);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-20 21:22:37 +01:00
|
|
|
|
private static SimpleDateFormat generatingVideoPathFormat;
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static File generateVideoPath(boolean secretChat) {
|
2015-05-21 23:27:27 +02:00
|
|
|
|
try {
|
2019-01-23 18:03:33 +01:00
|
|
|
|
File storageDir = getAlbumDir(secretChat);
|
2017-12-08 18:35:59 +01:00
|
|
|
|
Date date = new Date();
|
|
|
|
|
date.setTime(System.currentTimeMillis() + Utilities.random.nextInt(1000) + 1);
|
2022-03-20 21:22:37 +01:00
|
|
|
|
if (generatingVideoPathFormat == null) {
|
|
|
|
|
generatingVideoPathFormat = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.US);
|
|
|
|
|
}
|
|
|
|
|
String timeStamp = generatingVideoPathFormat.format(date);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
return new File(storageDir, "VID_" + timeStamp + ".mp4");
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String formatFileSize(long size) {
|
2019-03-03 21:40:48 +01:00
|
|
|
|
return formatFileSize(size, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String formatFileSize(long size, boolean removeZero) {
|
2015-05-21 23:27:27 +02:00
|
|
|
|
if (size < 1024) {
|
|
|
|
|
return String.format("%d B", size);
|
|
|
|
|
} else if (size < 1024 * 1024) {
|
2019-03-03 21:40:48 +01:00
|
|
|
|
float value = size / 1024.0f;
|
|
|
|
|
if (removeZero && (value - (int) value) * 10 == 0) {
|
|
|
|
|
return String.format("%d KB", (int) value);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format("%.1f KB", value);
|
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
} else if (size < 1024 * 1024 * 1024) {
|
2019-03-03 21:40:48 +01:00
|
|
|
|
float value = size / 1024.0f / 1024.0f;
|
|
|
|
|
if (removeZero && (value - (int) value) * 10 == 0) {
|
|
|
|
|
return String.format("%d MB", (int) value);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format("%.1f MB", value);
|
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
} else {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
float value = (int) (size / 1024L / 1024L) / 1000.0f;
|
2019-03-03 21:40:48 +01:00
|
|
|
|
if (removeZero && (value - (int) value) * 10 == 0) {
|
|
|
|
|
return String.format("%d GB", (int) value);
|
|
|
|
|
} else {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
return String.format("%.2f GB", value);
|
2019-03-03 21:40:48 +01:00
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static String formatShortDuration(int duration) {
|
|
|
|
|
return formatDuration(duration, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String formatLongDuration(int duration) {
|
|
|
|
|
return formatDuration(duration, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String formatDuration(int duration, boolean isLong) {
|
|
|
|
|
int h = duration / 3600;
|
|
|
|
|
int m = duration / 60 % 60;
|
|
|
|
|
int s = duration % 60;
|
|
|
|
|
if (h == 0) {
|
|
|
|
|
if (isLong) {
|
|
|
|
|
return String.format(Locale.US, "%02d:%02d", m, s);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d", m, s);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d:%02d", h, m, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-14 03:44:46 +02:00
|
|
|
|
public static String formatFullDuration(int duration) {
|
|
|
|
|
int h = duration / 3600;
|
|
|
|
|
int m = duration / 60 % 60;
|
|
|
|
|
int s = duration % 60;
|
|
|
|
|
if (duration < 0) {
|
|
|
|
|
return String.format(Locale.US, "-%02d:%02d:%02d", Math.abs(h), Math.abs(m), Math.abs(s));
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%02d:%02d:%02d", h, m, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-03 16:45:22 +01:00
|
|
|
|
public static String formatDurationNoHours(int duration, boolean isLong) {
|
|
|
|
|
int m = duration / 60;
|
|
|
|
|
int s = duration % 60;
|
|
|
|
|
if (isLong) {
|
|
|
|
|
return String.format(Locale.US, "%02d:%02d", m, s);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d", m, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static String formatShortDuration(int progress, int duration) {
|
|
|
|
|
return formatDuration(progress, duration, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String formatLongDuration(int progress, int duration) {
|
|
|
|
|
return formatDuration(progress, duration, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String formatDuration(int progress, int duration, boolean isLong) {
|
|
|
|
|
int h = duration / 3600;
|
|
|
|
|
int m = duration / 60 % 60;
|
|
|
|
|
int s = duration % 60;
|
|
|
|
|
|
|
|
|
|
int ph = progress / 3600;
|
|
|
|
|
int pm = progress / 60 % 60;
|
|
|
|
|
int ps = progress % 60;
|
|
|
|
|
|
|
|
|
|
if (duration == 0) {
|
|
|
|
|
if (ph == 0) {
|
|
|
|
|
if (isLong) {
|
|
|
|
|
return String.format(Locale.US, "%02d:%02d / -:--", pm, ps);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d / -:--", pm, ps);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d:%02d / -:--", ph, pm, ps);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (ph == 0 && h == 0) {
|
|
|
|
|
if (isLong) {
|
|
|
|
|
return String.format(Locale.US, "%02d:%02d / %02d:%02d", pm, ps, m, s);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d / %d:%02d", pm, ps, m, s);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d:%02d / %d:%02d:%02d", ph, pm, ps, h, m, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String formatVideoDuration(int progress, int duration) {
|
|
|
|
|
int h = duration / 3600;
|
|
|
|
|
int m = duration / 60 % 60;
|
|
|
|
|
int s = duration % 60;
|
|
|
|
|
|
|
|
|
|
int ph = progress / 3600;
|
|
|
|
|
int pm = progress / 60 % 60;
|
|
|
|
|
int ps = progress % 60;
|
|
|
|
|
|
|
|
|
|
if (ph == 0 && h == 0) {
|
|
|
|
|
return String.format(Locale.US, "%02d:%02d / %02d:%02d", pm, ps, m, s);
|
|
|
|
|
} else {
|
|
|
|
|
if (h == 0) {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d:%02d / %02d:%02d", ph, pm, ps, m, s);
|
|
|
|
|
} else if (ph == 0) {
|
|
|
|
|
return String.format(Locale.US, "%02d:%02d / %d:%02d:%02d", pm, ps, h, m, s);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return String.format(Locale.US, "%d:%02d:%02d / %d:%02d:%02d", ph, pm, ps, h, m, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-24 11:21:58 +02:00
|
|
|
|
public static String formatCount(int count) {
|
|
|
|
|
if (count < 1000) return Integer.toString(count);
|
|
|
|
|
|
|
|
|
|
ArrayList<String> strings = new ArrayList<>();
|
|
|
|
|
while (count != 0) {
|
|
|
|
|
int mod = count % 1000;
|
|
|
|
|
count /= 1000;
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
strings.add(String.format(Locale.ENGLISH, "%03d", mod));
|
|
|
|
|
} else {
|
|
|
|
|
strings.add(Integer.toString(mod));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
|
for (int i = strings.size() - 1; i >= 0; i--) {
|
|
|
|
|
stringBuilder.append(strings.get(i));
|
|
|
|
|
if (i != 0) {
|
|
|
|
|
stringBuilder.append(",");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stringBuilder.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static final String[] numbersSignatureArray = {"", "K", "M", "G", "T", "P"};
|
|
|
|
|
|
|
|
|
|
public static String formatWholeNumber(int v, int dif) {
|
|
|
|
|
if (v == 0) {
|
|
|
|
|
return "0";
|
|
|
|
|
}
|
|
|
|
|
float num_ = v;
|
|
|
|
|
int count = 0;
|
|
|
|
|
if (dif == 0) dif = v;
|
|
|
|
|
if (dif < 1000) {
|
|
|
|
|
return AndroidUtilities.formatCount(v);
|
|
|
|
|
}
|
|
|
|
|
while (dif >= 1000 && count < numbersSignatureArray.length - 1) {
|
|
|
|
|
dif /= 1000;
|
|
|
|
|
num_ /= 1000;
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
if (num_ < 0.1) {
|
|
|
|
|
return "0";
|
|
|
|
|
} else {
|
2020-09-30 15:48:47 +02:00
|
|
|
|
if ((num_ * 10)== (int) (num_ * 10)) {
|
2020-04-24 11:21:58 +02:00
|
|
|
|
return String.format(Locale.ENGLISH, "%s%s", AndroidUtilities.formatCount((int) num_), numbersSignatureArray[count]);
|
|
|
|
|
} else {
|
|
|
|
|
return String.format(Locale.ENGLISH, "%.1f%s", (int) (num_ * 10) / 10f, numbersSignatureArray[count]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 23:27:27 +02:00
|
|
|
|
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) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
buffer.write(b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
byte[] array = buffer.toByteArray();
|
|
|
|
|
try {
|
|
|
|
|
buffer.close();
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
}
|
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean copyFile(InputStream sourceFile, File destFile) throws IOException {
|
2021-11-09 02:49:31 +01:00
|
|
|
|
return copyFile(sourceFile, new FileOutputStream(destFile));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean copyFile(InputStream sourceFile, OutputStream out) throws IOException {
|
2015-05-21 23:27:27 +02:00
|
|
|
|
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 {
|
2019-09-10 12:56:11 +02:00
|
|
|
|
if (sourceFile.equals(destFile)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-05-21 23:27:27 +02:00
|
|
|
|
if (!destFile.exists()) {
|
|
|
|
|
destFile.createNewFile();
|
|
|
|
|
}
|
2019-05-14 14:08:05 +02:00
|
|
|
|
try (FileInputStream source = new FileInputStream(sourceFile); FileOutputStream destination = new FileOutputStream(destFile)) {
|
2015-05-21 23:27:27 +02:00
|
|
|
|
destination.getChannel().transferFrom(source.getChannel(), 0, source.getChannel().size());
|
|
|
|
|
} catch (Exception e) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
FileLog.e(e);
|
2015-05-21 23:27:27 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static void openDocument(MessageObject message, Activity activity, BaseFragment parentFragment) {
|
|
|
|
|
if (message == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
TLRPC.Document document = message.getDocument();
|
|
|
|
|
if (document == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
File f = null;
|
|
|
|
|
String fileName = message.messageOwner.media != null ? FileLoader.getAttachFileName(document) : "";
|
|
|
|
|
if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) {
|
|
|
|
|
f = new File(message.messageOwner.attachPath);
|
|
|
|
|
}
|
|
|
|
|
if (f == null || f != null && !f.exists()) {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToMessage(message.messageOwner);
|
2019-01-23 18:03:33 +01:00
|
|
|
|
}
|
|
|
|
|
if (f != null && f.exists()) {
|
|
|
|
|
if (parentFragment != null && f.getName().toLowerCase().endsWith("attheme")) {
|
2019-09-10 12:56:11 +02:00
|
|
|
|
Theme.ThemeInfo themeInfo = Theme.applyThemeFile(f, message.getDocumentName(), null, true);
|
2019-01-23 18:03:33 +01:00
|
|
|
|
if (themeInfo != null) {
|
2019-09-10 12:56:11 +02:00
|
|
|
|
parentFragment.presentFragment(new ThemePreviewActivity(themeInfo));
|
2019-01-23 18:03:33 +01:00
|
|
|
|
} else {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
|
|
|
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
|
|
|
|
builder.setMessage(LocaleController.getString("IncorrectTheme", R.string.IncorrectTheme));
|
|
|
|
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
|
|
|
|
|
parentFragment.showDialog(builder.create());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
String realMimeType = null;
|
|
|
|
|
try {
|
|
|
|
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
|
|
|
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
|
|
|
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) {
|
|
|
|
|
realMimeType = document.mime_type;
|
|
|
|
|
if (realMimeType == null || realMimeType.length() == 0) {
|
|
|
|
|
realMimeType = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 24) {
|
|
|
|
|
intent.setDataAndType(FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", f), realMimeType != null ? realMimeType : "text/plain");
|
|
|
|
|
} else {
|
|
|
|
|
intent.setDataAndType(Uri.fromFile(f), realMimeType != null ? realMimeType : "text/plain");
|
|
|
|
|
}
|
|
|
|
|
if (realMimeType != null) {
|
|
|
|
|
try {
|
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
if (activity == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
|
|
|
|
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
|
|
|
|
|
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
|
|
|
|
|
builder.setMessage(LocaleController.formatString("NoHandleAppInstalled", R.string.NoHandleAppInstalled, message.getDocument().mime_type));
|
|
|
|
|
if (parentFragment != null) {
|
|
|
|
|
parentFragment.showDialog(builder.create());
|
|
|
|
|
} else {
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
|
public static boolean openForView(File f, String fileName, String mimeType, final Activity activity, Theme.ResourcesProvider resourcesProvider) {
|
2016-06-24 12:27:15 +02:00
|
|
|
|
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) {
|
2021-06-25 02:43:10 +02:00
|
|
|
|
realMimeType = mimeType;
|
2016-06-24 12:27:15 +02:00
|
|
|
|
if (realMimeType == null || realMimeType.length() == 0) {
|
|
|
|
|
realMimeType = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
|
}
|
2022-03-11 17:49:54 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && realMimeType != null && realMimeType.equals("application/vnd.android.package-archive") && !ApplicationLoader.applicationContext.getPackageManager().canRequestPackageInstalls()) {
|
|
|
|
|
AlertsCreator.createApkRestrictedDialog(activity, resourcesProvider).show();
|
2020-03-30 14:00:09 +02:00
|
|
|
|
return true;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
}
|
2022-03-11 17:49:54 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
2016-10-11 13:57:01 +02:00
|
|
|
|
intent.setDataAndType(FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", f), realMimeType != null ? realMimeType : "text/plain");
|
2017-03-31 01:58:05 +02:00
|
|
|
|
} else {
|
|
|
|
|
intent.setDataAndType(Uri.fromFile(f), realMimeType != null ? realMimeType : "text/plain");
|
|
|
|
|
}
|
|
|
|
|
if (realMimeType != null) {
|
|
|
|
|
try {
|
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
|
} catch (Exception e) {
|
2022-03-11 17:49:54 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
intent.setDataAndType(FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", f), "text/plain");
|
|
|
|
|
} else {
|
|
|
|
|
intent.setDataAndType(Uri.fromFile(f), "text/plain");
|
|
|
|
|
}
|
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
activity.startActivityForResult(intent, 500);
|
|
|
|
|
}
|
2020-03-30 14:00:09 +02:00
|
|
|
|
return true;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
}
|
2020-03-30 14:00:09 +02:00
|
|
|
|
return false;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-20 07:54:41 +02:00
|
|
|
|
public static boolean openForView(MessageObject message, Activity activity, Theme.ResourcesProvider resourcesProvider) {
|
2021-06-25 02:43:10 +02:00
|
|
|
|
File f = null;
|
|
|
|
|
if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) {
|
|
|
|
|
f = new File(message.messageOwner.attachPath);
|
|
|
|
|
}
|
|
|
|
|
if (f == null || !f.exists()) {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
f = FileLoader.getInstance(message.currentAccount).getPathToMessage(message.messageOwner);
|
2021-06-25 02:43:10 +02:00
|
|
|
|
}
|
|
|
|
|
String mimeType = message.type == 9 || message.type == 0 ? message.getMimeType() : null;
|
2021-09-20 07:54:41 +02:00
|
|
|
|
return openForView(f, message.getFileName(), mimeType, activity, resourcesProvider);
|
2021-06-25 02:43:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean openForView(TLRPC.Document document, boolean forceCache, Activity activity) {
|
|
|
|
|
String fileName = FileLoader.getAttachFileName(document);
|
2022-06-21 04:51:00 +02:00
|
|
|
|
File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true);
|
2021-09-20 07:54:41 +02:00
|
|
|
|
return openForView(f, fileName, document.mime_type, activity, null);
|
2021-06-25 02:43:10 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 11:52:40 +01:00
|
|
|
|
public static SpannableStringBuilder formatSpannableSimple(String format, CharSequence... cs) {
|
|
|
|
|
return formatSpannable(format, i -> "%s", cs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static SpannableStringBuilder formatSpannable(String format, CharSequence... cs) {
|
|
|
|
|
if (format.contains("%s"))
|
|
|
|
|
return formatSpannableSimple(format, cs);
|
|
|
|
|
return formatSpannable(format, i -> "%" + (i + 1) + "$s", cs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static SpannableStringBuilder formatSpannable(String format, GenericProvider<Integer, String> keysProvider, CharSequence... cs) {
|
|
|
|
|
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(format);
|
|
|
|
|
for (int i = 0; i < cs.length; i++) {
|
|
|
|
|
String key = keysProvider.provide(i);
|
|
|
|
|
int j = format.indexOf(key);
|
|
|
|
|
if (j != -1) {
|
|
|
|
|
stringBuilder.replace(j, j + key.length(), cs[i]);
|
|
|
|
|
format = format.substring(0, j) + cs[i].toString() + format.substring(j + key.length());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return stringBuilder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static CharSequence replaceTwoNewLinesToOne(CharSequence original) {
|
|
|
|
|
char[] buf = new char[2];
|
|
|
|
|
if (original instanceof StringBuilder) {
|
|
|
|
|
StringBuilder stringBuilder = (StringBuilder) original;
|
|
|
|
|
for (int a = 0, N = original.length(); a < N - 2; a++) {
|
|
|
|
|
stringBuilder.getChars(a, a + 2, buf, 0);
|
|
|
|
|
if (buf[0] == '\n' && buf[1] == '\n') {
|
|
|
|
|
stringBuilder = stringBuilder.replace(a, a + 2, "\n");
|
|
|
|
|
a--;
|
|
|
|
|
N--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return original;
|
|
|
|
|
} else if (original instanceof SpannableStringBuilder) {
|
|
|
|
|
SpannableStringBuilder stringBuilder = (SpannableStringBuilder) original;
|
|
|
|
|
for (int a = 0, N = original.length(); a < N - 2; a++) {
|
|
|
|
|
stringBuilder.getChars(a, a + 2, buf, 0);
|
|
|
|
|
if (buf[0] == '\n' && buf[1] == '\n') {
|
|
|
|
|
stringBuilder = stringBuilder.replace(a, a + 2, "\n");
|
|
|
|
|
a--;
|
|
|
|
|
N--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return original;
|
|
|
|
|
}
|
|
|
|
|
return original.toString().replace("\n\n", "\n");
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-26 10:03:38 +02:00
|
|
|
|
public static CharSequence replaceNewLines(CharSequence original) {
|
|
|
|
|
if (original instanceof StringBuilder) {
|
|
|
|
|
StringBuilder stringBuilder = (StringBuilder) original;
|
|
|
|
|
for (int a = 0, N = original.length(); a < N; a++) {
|
|
|
|
|
if (original.charAt(a) == '\n') {
|
|
|
|
|
stringBuilder.setCharAt(a, ' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-30 11:52:40 +01:00
|
|
|
|
return original;
|
2020-07-26 10:03:38 +02:00
|
|
|
|
} else if (original instanceof SpannableStringBuilder) {
|
|
|
|
|
SpannableStringBuilder stringBuilder = (SpannableStringBuilder) original;
|
|
|
|
|
for (int a = 0, N = original.length(); a < N; a++) {
|
|
|
|
|
if (original.charAt(a) == '\n') {
|
|
|
|
|
stringBuilder.replace(a, a + 1, " ");
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-30 11:52:40 +01:00
|
|
|
|
return original;
|
2020-07-26 10:03:38 +02:00
|
|
|
|
}
|
|
|
|
|
return original.toString().replace('\n', ' ');
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-30 15:48:47 +02:00
|
|
|
|
public static boolean openForView(TLObject media, Activity activity) {
|
2017-03-31 01:58:05 +02:00
|
|
|
|
if (media == null || activity == null) {
|
2020-09-30 15:48:47 +02:00
|
|
|
|
return false;
|
2017-03-31 01:58:05 +02:00
|
|
|
|
}
|
|
|
|
|
String fileName = FileLoader.getAttachFileName(media);
|
2022-06-21 04:51:00 +02:00
|
|
|
|
File f = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(media, true);
|
2017-03-31 01:58:05 +02:00
|
|
|
|
if (f != null && f.exists()) {
|
|
|
|
|
String realMimeType = null;
|
|
|
|
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
|
|
|
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
|
|
|
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 (media instanceof TLRPC.TL_document) {
|
|
|
|
|
realMimeType = ((TLRPC.TL_document) media).mime_type;
|
|
|
|
|
}
|
|
|
|
|
if (realMimeType == null || realMimeType.length() == 0) {
|
|
|
|
|
realMimeType = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
2020-09-30 15:48:47 +02:00
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
2016-06-24 12:27:15 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static boolean isBannedForever(TLRPC.TL_chatBannedRights rights) {
|
|
|
|
|
return rights == null || Math.abs(rights.until_date - System.currentTimeMillis() / 1000) > 5 * 365 * 24 * 60 * 60;
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-03 21:40:48 +01:00
|
|
|
|
public static void setRectToRect(Matrix matrix, RectF src, RectF dst, int rotation, boolean translate) {
|
2016-10-11 13:57:01 +02:00
|
|
|
|
float tx, sx;
|
|
|
|
|
float ty, sy;
|
2019-03-03 21:40:48 +01:00
|
|
|
|
boolean xLarger = false;
|
2016-10-11 13:57:01 +02:00
|
|
|
|
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();
|
|
|
|
|
}
|
2019-03-03 21:40:48 +01:00
|
|
|
|
if (sx < sy) {
|
|
|
|
|
sx = sy;
|
|
|
|
|
xLarger = true;
|
|
|
|
|
} else {
|
|
|
|
|
sy = sx;
|
2016-10-11 13:57:01 +02:00
|
|
|
|
}
|
2019-03-03 21:40:48 +01:00
|
|
|
|
if (translate) {
|
|
|
|
|
matrix.setTranslate(dst.left, dst.top);
|
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-03 21:40:48 +01:00
|
|
|
|
if (translate) {
|
|
|
|
|
tx = -src.left * sx;
|
|
|
|
|
ty = -src.top * sy;
|
|
|
|
|
} else {
|
|
|
|
|
tx = dst.left - src.left * sx;
|
|
|
|
|
ty = dst.top - src.top * sy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float diff;
|
|
|
|
|
if (xLarger) {
|
|
|
|
|
diff = dst.width() - src.width() * sy;
|
|
|
|
|
} else {
|
|
|
|
|
diff = dst.height() - src.height() * sy;
|
|
|
|
|
}
|
|
|
|
|
diff = diff / 2.0f;
|
|
|
|
|
if (xLarger) {
|
|
|
|
|
tx += diff;
|
|
|
|
|
} else {
|
|
|
|
|
ty += diff;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 13:57:01 +02:00
|
|
|
|
matrix.preScale(sx, sy);
|
2019-03-03 21:40:48 +01:00
|
|
|
|
if (translate) {
|
|
|
|
|
matrix.preTranslate(tx, ty);
|
|
|
|
|
}
|
2016-10-11 13:57:01 +02:00
|
|
|
|
}
|
2017-07-08 18:32:04 +02:00
|
|
|
|
|
2022-06-21 04:51:00 +02:00
|
|
|
|
public static Vibrator getVibrator() {
|
|
|
|
|
if (vibrator == null) {
|
|
|
|
|
vibrator = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE);
|
|
|
|
|
}
|
|
|
|
|
return vibrator;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static boolean isAccessibilityTouchExplorationEnabled() {
|
|
|
|
|
if (accessibilityManager == null) {
|
|
|
|
|
accessibilityManager = (AccessibilityManager) ApplicationLoader.applicationContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
|
|
|
|
}
|
|
|
|
|
return accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled();
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 18:32:04 +02:00
|
|
|
|
public static boolean handleProxyIntent(Activity activity, Intent intent) {
|
|
|
|
|
if (intent == null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Uri data = intent.getData();
|
|
|
|
|
if (data != null) {
|
|
|
|
|
String user = null;
|
|
|
|
|
String password = null;
|
|
|
|
|
String port = null;
|
|
|
|
|
String address = null;
|
2018-07-30 04:07:02 +02:00
|
|
|
|
String secret = null;
|
2017-07-08 18:32:04 +02:00
|
|
|
|
String scheme = data.getScheme();
|
|
|
|
|
if (scheme != null) {
|
|
|
|
|
if ((scheme.equals("http") || scheme.equals("https"))) {
|
|
|
|
|
String host = data.getHost().toLowerCase();
|
2019-01-23 18:03:33 +01:00
|
|
|
|
if (host.equals("telegram.me") || host.equals("t.me") || host.equals("telegram.dog")) {
|
2017-07-08 18:32:04 +02:00
|
|
|
|
String path = data.getPath();
|
|
|
|
|
if (path != null) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (path.startsWith("/socks") || path.startsWith("/proxy")) {
|
2017-07-08 18:32:04 +02:00
|
|
|
|
address = data.getQueryParameter("server");
|
2021-02-23 12:53:38 +01:00
|
|
|
|
if (AndroidUtilities.checkHostForPunycode(address)) {
|
|
|
|
|
address = IDN.toASCII(address, IDN.ALLOW_UNASSIGNED);
|
|
|
|
|
}
|
2017-07-08 18:32:04 +02:00
|
|
|
|
port = data.getQueryParameter("port");
|
|
|
|
|
user = data.getQueryParameter("user");
|
|
|
|
|
password = data.getQueryParameter("pass");
|
2018-07-30 04:07:02 +02:00
|
|
|
|
secret = data.getQueryParameter("secret");
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (scheme.equals("tg")) {
|
|
|
|
|
String url = data.toString();
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (url.startsWith("tg:proxy") || url.startsWith("tg://proxy") || url.startsWith("tg:socks") || url.startsWith("tg://socks")) {
|
|
|
|
|
url = url.replace("tg:proxy", "tg://telegram.org").replace("tg://proxy", "tg://telegram.org").replace("tg://socks", "tg://telegram.org").replace("tg:socks", "tg://telegram.org");
|
2017-07-08 18:32:04 +02:00
|
|
|
|
data = Uri.parse(url);
|
|
|
|
|
address = data.getQueryParameter("server");
|
2021-02-23 12:53:38 +01:00
|
|
|
|
if (AndroidUtilities.checkHostForPunycode(address)) {
|
|
|
|
|
address = IDN.toASCII(address, IDN.ALLOW_UNASSIGNED);
|
|
|
|
|
}
|
2017-07-08 18:32:04 +02:00
|
|
|
|
port = data.getQueryParameter("port");
|
|
|
|
|
user = data.getQueryParameter("user");
|
|
|
|
|
password = data.getQueryParameter("pass");
|
2018-07-30 04:07:02 +02:00
|
|
|
|
secret = data.getQueryParameter("secret");
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!TextUtils.isEmpty(address) && !TextUtils.isEmpty(port)) {
|
|
|
|
|
if (user == null) {
|
|
|
|
|
user = "";
|
|
|
|
|
}
|
|
|
|
|
if (password == null) {
|
|
|
|
|
password = "";
|
|
|
|
|
}
|
2018-07-30 04:07:02 +02:00
|
|
|
|
if (secret == null) {
|
|
|
|
|
secret = "";
|
|
|
|
|
}
|
|
|
|
|
showProxyAlert(activity, address, port, user, password, secret);
|
2017-07-08 18:32:04 +02:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static boolean shouldEnableAnimation() {
|
|
|
|
|
if (Build.VERSION.SDK_INT < 26 || Build.VERSION.SDK_INT >= 28) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
PowerManager powerManager = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
|
|
|
|
|
if (powerManager.isPowerSaveMode()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
float scale = Settings.Global.getFloat(ApplicationLoader.applicationContext.getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f);
|
|
|
|
|
if (scale <= 0.0f) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-30 04:07:02 +02:00
|
|
|
|
public static void showProxyAlert(Activity activity, final String address, final String port, final String user, final String password, final String secret) {
|
|
|
|
|
BottomSheet.Builder builder = new BottomSheet.Builder(activity);
|
|
|
|
|
final Runnable dismissRunnable = builder.getDismissRunnable();
|
|
|
|
|
|
|
|
|
|
builder.setApplyTopPadding(false);
|
|
|
|
|
builder.setApplyBottomPadding(false);
|
|
|
|
|
LinearLayout linearLayout = new LinearLayout(activity);
|
|
|
|
|
builder.setCustomView(linearLayout);
|
|
|
|
|
linearLayout.setOrientation(LinearLayout.VERTICAL);
|
|
|
|
|
if (!TextUtils.isEmpty(secret)) {
|
|
|
|
|
TextView titleTextView = new TextView(activity);
|
|
|
|
|
titleTextView.setText(LocaleController.getString("UseProxyTelegramInfo2", R.string.UseProxyTelegramInfo2));
|
|
|
|
|
titleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray4));
|
|
|
|
|
titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
|
|
|
|
|
titleTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
|
|
|
|
|
linearLayout.addView(titleTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 8, 17, 8));
|
|
|
|
|
|
|
|
|
|
View lineView = new View(activity);
|
|
|
|
|
lineView.setBackgroundColor(Theme.getColor(Theme.key_divider));
|
|
|
|
|
linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
|
|
|
|
}
|
|
|
|
|
for (int a = 0; a < 5; a++) {
|
|
|
|
|
String text = null;
|
|
|
|
|
String detail = null;
|
|
|
|
|
if (a == 0) {
|
|
|
|
|
text = address;
|
|
|
|
|
detail = LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress);
|
|
|
|
|
} else if (a == 1) {
|
|
|
|
|
text = "" + port;
|
|
|
|
|
detail = LocaleController.getString("UseProxyPort", R.string.UseProxyPort);
|
|
|
|
|
} else if (a == 2) {
|
|
|
|
|
text = secret;
|
|
|
|
|
detail = LocaleController.getString("UseProxySecret", R.string.UseProxySecret);
|
|
|
|
|
} else if (a == 3) {
|
|
|
|
|
text = user;
|
|
|
|
|
detail = LocaleController.getString("UseProxyUsername", R.string.UseProxyUsername);
|
|
|
|
|
} else if (a == 4) {
|
|
|
|
|
text = password;
|
|
|
|
|
detail = LocaleController.getString("UseProxyPassword", R.string.UseProxyPassword);
|
|
|
|
|
}
|
|
|
|
|
if (TextUtils.isEmpty(text)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
TextDetailSettingsCell cell = new TextDetailSettingsCell(activity);
|
|
|
|
|
cell.setTextAndValue(text, detail, true);
|
|
|
|
|
cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack));
|
|
|
|
|
cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3));
|
|
|
|
|
linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));
|
|
|
|
|
if (a == 2) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
2018-07-30 04:07:02 +02:00
|
|
|
|
|
|
|
|
|
PickerBottomLayout pickerBottomLayout = new PickerBottomLayout(activity, false);
|
|
|
|
|
pickerBottomLayout.setBackgroundColor(Theme.getColor(Theme.key_dialogBackground));
|
|
|
|
|
linearLayout.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM));
|
|
|
|
|
pickerBottomLayout.cancelButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
|
|
|
|
|
pickerBottomLayout.cancelButton.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
|
|
|
|
|
pickerBottomLayout.cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase());
|
2019-01-23 18:03:33 +01:00
|
|
|
|
pickerBottomLayout.cancelButton.setOnClickListener(view -> dismissRunnable.run());
|
2018-07-30 04:07:02 +02:00
|
|
|
|
pickerBottomLayout.doneButtonTextView.setTextColor(Theme.getColor(Theme.key_dialogTextBlue2));
|
|
|
|
|
pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0);
|
|
|
|
|
pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE);
|
|
|
|
|
pickerBottomLayout.doneButtonTextView.setText(LocaleController.getString("ConnectingConnectProxy", R.string.ConnectingConnectProxy).toUpperCase());
|
2019-01-23 18:03:33 +01:00
|
|
|
|
pickerBottomLayout.doneButton.setOnClickListener(v -> {
|
|
|
|
|
SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit();
|
|
|
|
|
editor.putBoolean("proxy_enabled", true);
|
|
|
|
|
editor.putString("proxy_ip", address);
|
|
|
|
|
int p = Utilities.parseInt(port);
|
|
|
|
|
editor.putInt("proxy_port", p);
|
|
|
|
|
|
|
|
|
|
SharedConfig.ProxyInfo info;
|
|
|
|
|
if (TextUtils.isEmpty(secret)) {
|
|
|
|
|
editor.remove("proxy_secret");
|
|
|
|
|
if (TextUtils.isEmpty(password)) {
|
2018-07-30 04:07:02 +02:00
|
|
|
|
editor.remove("proxy_pass");
|
2019-01-23 18:03:33 +01:00
|
|
|
|
} else {
|
|
|
|
|
editor.putString("proxy_pass", password);
|
|
|
|
|
}
|
|
|
|
|
if (TextUtils.isEmpty(user)) {
|
2017-07-08 18:32:04 +02:00
|
|
|
|
editor.remove("proxy_user");
|
2019-01-23 18:03:33 +01:00
|
|
|
|
} else {
|
|
|
|
|
editor.putString("proxy_user", user);
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
|
info = new SharedConfig.ProxyInfo(address, p, user, password, "");
|
|
|
|
|
} else {
|
|
|
|
|
editor.remove("proxy_pass");
|
|
|
|
|
editor.remove("proxy_user");
|
|
|
|
|
editor.putString("proxy_secret", secret);
|
|
|
|
|
info = new SharedConfig.ProxyInfo(address, p, "", "", secret);
|
|
|
|
|
}
|
|
|
|
|
editor.commit();
|
2018-07-30 04:07:02 +02:00
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
SharedConfig.currentProxy = SharedConfig.addProxy(info);
|
2018-07-30 04:07:02 +02:00
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
ConnectionsManager.setProxySettings(true, address, p, user, password, secret);
|
|
|
|
|
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
|
|
|
|
|
dismissRunnable.run();
|
2017-07-08 18:32:04 +02:00
|
|
|
|
});
|
2018-07-30 04:07:02 +02:00
|
|
|
|
builder.show();
|
2017-07-08 18:32:04 +02:00
|
|
|
|
}
|
2018-08-27 10:33:11 +02:00
|
|
|
|
|
2019-05-14 14:08:05 +02:00
|
|
|
|
@SuppressLint("PrivateApi")
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static String getSystemProperty(String key) {
|
|
|
|
|
try {
|
|
|
|
|
Class props = Class.forName("android.os.SystemProperties");
|
|
|
|
|
return (String) props.getMethod("get", String.class).invoke(null, key);
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
}
|
2018-08-27 10:33:11 +02:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2019-01-23 18:03:33 +01:00
|
|
|
|
|
2020-04-24 11:28:11 +02:00
|
|
|
|
public static void fixGoogleMapsBug() { //https://issuetracker.google.com/issues/154855417#comment301
|
|
|
|
|
SharedPreferences googleBug = ApplicationLoader.applicationContext.getSharedPreferences("google_bug_154855417", Context.MODE_PRIVATE);
|
|
|
|
|
if (!googleBug.contains("fixed")) {
|
|
|
|
|
File corruptedZoomTables = new File(ApplicationLoader.getFilesDirFixed(), "ZoomTables.data");
|
|
|
|
|
corruptedZoomTables.delete();
|
|
|
|
|
googleBug.edit().putBoolean("fixed", true).apply();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 18:03:33 +01:00
|
|
|
|
public static CharSequence concat(CharSequence... text) {
|
|
|
|
|
if (text.length == 0) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (text.length == 1) {
|
|
|
|
|
return text[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean spanned = false;
|
|
|
|
|
for (CharSequence piece : text) {
|
|
|
|
|
if (piece instanceof Spanned) {
|
|
|
|
|
spanned = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (spanned) {
|
|
|
|
|
final SpannableStringBuilder ssb = new SpannableStringBuilder();
|
|
|
|
|
for (CharSequence piece : text) {
|
|
|
|
|
// If a piece is null, we append the string "null" for compatibility with the
|
|
|
|
|
// behavior of StringBuilder and the behavior of the concat() method in earlier
|
|
|
|
|
// versions of Android.
|
|
|
|
|
ssb.append(piece == null ? "null" : piece);
|
|
|
|
|
}
|
|
|
|
|
return new SpannedString(ssb);
|
|
|
|
|
} else {
|
|
|
|
|
final StringBuilder sb = new StringBuilder();
|
|
|
|
|
for (CharSequence piece : text) {
|
|
|
|
|
sb.append(piece);
|
|
|
|
|
}
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-08 03:30:32 +01:00
|
|
|
|
|
|
|
|
|
public static float[] RGBtoHSB(int r, int g, int b) {
|
|
|
|
|
float hue, saturation, brightness;
|
|
|
|
|
float[] hsbvals = new float[3];
|
2020-07-26 10:03:38 +02:00
|
|
|
|
int cmax = Math.max(r, g);
|
2019-02-08 03:30:32 +01:00
|
|
|
|
if (b > cmax) {
|
|
|
|
|
cmax = b;
|
|
|
|
|
}
|
2020-07-26 10:03:38 +02:00
|
|
|
|
int cmin = Math.min(r, g);
|
2019-02-08 03:30:32 +01:00
|
|
|
|
if (b < cmin) {
|
|
|
|
|
cmin = b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
brightness = ((float) cmax) / 255.0f;
|
|
|
|
|
if (cmax != 0) {
|
|
|
|
|
saturation = ((float) (cmax - cmin)) / ((float) cmax);
|
|
|
|
|
} else {
|
|
|
|
|
saturation = 0;
|
|
|
|
|
}
|
|
|
|
|
if (saturation == 0) {
|
|
|
|
|
hue = 0;
|
|
|
|
|
} else {
|
|
|
|
|
float redc = ((float) (cmax - r)) / ((float) (cmax - cmin));
|
|
|
|
|
float greenc = ((float) (cmax - g)) / ((float) (cmax - cmin));
|
|
|
|
|
float bluec = ((float) (cmax - b)) / ((float) (cmax - cmin));
|
|
|
|
|
if (r == cmax) {
|
|
|
|
|
hue = bluec - greenc;
|
|
|
|
|
} else if (g == cmax) {
|
|
|
|
|
hue = 2.0f + redc - bluec;
|
|
|
|
|
} else {
|
|
|
|
|
hue = 4.0f + greenc - redc;
|
|
|
|
|
}
|
|
|
|
|
hue = hue / 6.0f;
|
|
|
|
|
if (hue < 0) {
|
|
|
|
|
hue = hue + 1.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
hsbvals[0] = hue;
|
|
|
|
|
hsbvals[1] = saturation;
|
|
|
|
|
hsbvals[2] = brightness;
|
|
|
|
|
return hsbvals;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int HSBtoRGB(float hue, float saturation, float brightness) {
|
|
|
|
|
int r = 0, g = 0, b = 0;
|
|
|
|
|
if (saturation == 0) {
|
|
|
|
|
r = g = b = (int) (brightness * 255.0f + 0.5f);
|
|
|
|
|
} else {
|
|
|
|
|
float h = (hue - (float) Math.floor(hue)) * 6.0f;
|
|
|
|
|
float f = h - (float) java.lang.Math.floor(h);
|
|
|
|
|
float p = brightness * (1.0f - saturation);
|
|
|
|
|
float q = brightness * (1.0f - saturation * f);
|
|
|
|
|
float t = brightness * (1.0f - (saturation * (1.0f - f)));
|
|
|
|
|
switch ((int) h) {
|
|
|
|
|
case 0:
|
|
|
|
|
r = (int) (brightness * 255.0f + 0.5f);
|
|
|
|
|
g = (int) (t * 255.0f + 0.5f);
|
|
|
|
|
b = (int) (p * 255.0f + 0.5f);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
r = (int) (q * 255.0f + 0.5f);
|
|
|
|
|
g = (int) (brightness * 255.0f + 0.5f);
|
|
|
|
|
b = (int) (p * 255.0f + 0.5f);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
r = (int) (p * 255.0f + 0.5f);
|
|
|
|
|
g = (int) (brightness * 255.0f + 0.5f);
|
|
|
|
|
b = (int) (t * 255.0f + 0.5f);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
r = (int) (p * 255.0f + 0.5f);
|
|
|
|
|
g = (int) (q * 255.0f + 0.5f);
|
|
|
|
|
b = (int) (brightness * 255.0f + 0.5f);
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
r = (int) (t * 255.0f + 0.5f);
|
|
|
|
|
g = (int) (p * 255.0f + 0.5f);
|
|
|
|
|
b = (int) (brightness * 255.0f + 0.5f);
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
r = (int) (brightness * 255.0f + 0.5f);
|
|
|
|
|
g = (int) (p * 255.0f + 0.5f);
|
|
|
|
|
b = (int) (q * 255.0f + 0.5f);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0xff000000 | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static float computePerceivedBrightness(int color) {
|
|
|
|
|
return (Color.red(color) * 0.2126f + Color.green(color) * 0.7152f + Color.blue(color) * 0.0722f) / 255f;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-08 03:30:32 +01:00
|
|
|
|
public static int getPatternColor(int color) {
|
2021-06-25 02:43:10 +02:00
|
|
|
|
return getPatternColor(color, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getPatternColor(int color, boolean alwaysDark) {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
float[] hsb = RGBtoHSB(Color.red(color), Color.green(color), Color.blue(color));
|
2019-02-08 03:30:32 +01:00
|
|
|
|
if (hsb[1] > 0.0f || (hsb[2] < 1.0f && hsb[2] > 0.0f)) {
|
2021-06-25 02:43:10 +02:00
|
|
|
|
hsb[1] = Math.min(1.0f, hsb[1] + (alwaysDark ? 0.15f : 0.05f) + 0.1f * (1.0f - hsb[1]));
|
2019-02-08 03:30:32 +01:00
|
|
|
|
}
|
2021-06-25 02:43:10 +02:00
|
|
|
|
if (alwaysDark || hsb[2] > 0.5f) {
|
2019-02-08 03:30:32 +01:00
|
|
|
|
hsb[2] = Math.max(0.0f, hsb[2] * 0.65f);
|
|
|
|
|
} else {
|
|
|
|
|
hsb[2] = Math.max(0.0f, Math.min(1.0f, 1.0f - hsb[2] * 0.65f));
|
|
|
|
|
}
|
2021-06-25 02:43:10 +02:00
|
|
|
|
return HSBtoRGB(hsb[0], hsb[1], hsb[2]) & (alwaysDark ? 0x99ffffff : 0x66ffffff);
|
2019-02-08 03:30:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getPatternSideColor(int color) {
|
2019-05-14 14:08:05 +02:00
|
|
|
|
float[] hsb = RGBtoHSB(Color.red(color), Color.green(color), Color.blue(color));
|
2019-02-08 03:30:32 +01:00
|
|
|
|
hsb[1] = Math.min(1.0f, hsb[1] + 0.05f);
|
|
|
|
|
if (hsb[2] > 0.5f) {
|
|
|
|
|
hsb[2] = Math.max(0.0f, hsb[2] * 0.90f);
|
|
|
|
|
} else{
|
|
|
|
|
hsb[2] = Math.max(0.0f, hsb[2] * 0.90f);
|
|
|
|
|
}
|
|
|
|
|
return HSBtoRGB(hsb[0], hsb[1], hsb[2]) | 0xff000000;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static int getWallpaperRotation(int angle, boolean iOS) {
|
|
|
|
|
if (iOS) {
|
|
|
|
|
angle += 180;
|
|
|
|
|
} else {
|
|
|
|
|
angle -= 180;
|
|
|
|
|
}
|
|
|
|
|
while (angle >= 360) {
|
|
|
|
|
angle -= 360;
|
|
|
|
|
}
|
|
|
|
|
while (angle < 0) {
|
|
|
|
|
angle += 360;
|
|
|
|
|
}
|
|
|
|
|
return angle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String getWallPaperUrl(Object object) {
|
2019-02-08 03:30:32 +01:00
|
|
|
|
String link;
|
|
|
|
|
if (object instanceof TLRPC.TL_wallPaper) {
|
|
|
|
|
TLRPC.TL_wallPaper wallPaper = (TLRPC.TL_wallPaper) object;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
link = "https://" + MessagesController.getInstance(UserConfig.selectedAccount).linkPrefix + "/bg/" + wallPaper.slug;
|
2019-02-08 03:30:32 +01:00
|
|
|
|
StringBuilder modes = new StringBuilder();
|
|
|
|
|
if (wallPaper.settings != null) {
|
|
|
|
|
if (wallPaper.settings.blur) {
|
|
|
|
|
modes.append("blur");
|
|
|
|
|
}
|
|
|
|
|
if (wallPaper.settings.motion) {
|
|
|
|
|
if (modes.length() > 0) {
|
|
|
|
|
modes.append("+");
|
|
|
|
|
}
|
|
|
|
|
modes.append("motion");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (modes.length() > 0) {
|
|
|
|
|
link += "?mode=" + modes.toString();
|
|
|
|
|
}
|
|
|
|
|
} else if (object instanceof WallpapersListActivity.ColorWallpaper) {
|
|
|
|
|
WallpapersListActivity.ColorWallpaper wallPaper = (WallpapersListActivity.ColorWallpaper) object;
|
2019-12-31 14:08:08 +01:00
|
|
|
|
link = wallPaper.getUrl();
|
2019-02-08 03:30:32 +01:00
|
|
|
|
} else {
|
|
|
|
|
link = null;
|
|
|
|
|
}
|
|
|
|
|
return link;
|
|
|
|
|
}
|
2019-03-03 21:40:48 +01:00
|
|
|
|
|
|
|
|
|
public static float distanceInfluenceForSnapDuration(float f) {
|
|
|
|
|
f -= 0.5F;
|
|
|
|
|
f *= 0.47123894F;
|
2020-07-26 10:03:38 +02:00
|
|
|
|
return (float) Math.sin(f);
|
2019-03-03 21:40:48 +01:00
|
|
|
|
}
|
2019-05-14 14:08:05 +02:00
|
|
|
|
|
|
|
|
|
public static void makeAccessibilityAnnouncement(CharSequence what) {
|
|
|
|
|
AccessibilityManager am = (AccessibilityManager) ApplicationLoader.applicationContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
|
|
|
|
if (am.isEnabled()) {
|
|
|
|
|
AccessibilityEvent ev = AccessibilityEvent.obtain();
|
|
|
|
|
ev.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
|
|
|
|
ev.getText().add(what);
|
|
|
|
|
am.sendAccessibilityEvent(ev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getOffsetColor(int color1, int color2, float offset, float alpha) {
|
|
|
|
|
int rF = Color.red(color2);
|
|
|
|
|
int gF = Color.green(color2);
|
|
|
|
|
int bF = Color.blue(color2);
|
|
|
|
|
int aF = Color.alpha(color2);
|
|
|
|
|
int rS = Color.red(color1);
|
|
|
|
|
int gS = Color.green(color1);
|
|
|
|
|
int bS = Color.blue(color1);
|
|
|
|
|
int aS = Color.alpha(color1);
|
|
|
|
|
return Color.argb((int) ((aS + (aF - aS) * offset) * alpha), (int) (rS + (rF - rS) * offset), (int) (gS + (gF - gS) * offset), (int) (bS + (bF - bS) * offset));
|
|
|
|
|
}
|
2019-07-18 15:01:39 +02:00
|
|
|
|
|
|
|
|
|
public static int indexOfIgnoreCase(final String origin, final String searchStr) {
|
|
|
|
|
if (searchStr.isEmpty() || origin.isEmpty()) {
|
|
|
|
|
return origin.indexOf(searchStr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < origin.length(); i++) {
|
|
|
|
|
if (i + searchStr.length() > origin.length()) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
int j = 0;
|
|
|
|
|
int ii = i;
|
|
|
|
|
while (ii < origin.length() && j < searchStr.length()) {
|
|
|
|
|
char c = Character.toLowerCase(origin.charAt(ii));
|
|
|
|
|
char c2 = Character.toLowerCase(searchStr.charAt(j));
|
|
|
|
|
if (c != c2) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
j++;
|
|
|
|
|
ii++;
|
|
|
|
|
}
|
|
|
|
|
if (j == searchStr.length()) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2019-12-31 14:08:08 +01:00
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static int lerp(int a, int b, float f) {
|
|
|
|
|
return (int) (a + f * (b - a));
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static float lerp(float a, float b, float f) {
|
|
|
|
|
return a + f * (b - a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static float lerp(float[] ab, float f) {
|
|
|
|
|
return lerp(ab[0], ab[1], f);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static int lerpColor(int a, int b, float f) {
|
|
|
|
|
return Color.argb(
|
|
|
|
|
lerp(Color.alpha(a), Color.alpha(b), f),
|
|
|
|
|
lerp(Color.red(a), Color.red(b), f),
|
|
|
|
|
lerp(Color.green(a), Color.green(b), f),
|
|
|
|
|
lerp(Color.blue(a), Color.blue(b), f)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void lerp(RectF a, RectF b, float f, RectF to) {
|
|
|
|
|
if (to != null) {
|
|
|
|
|
to.set(
|
|
|
|
|
AndroidUtilities.lerp(a.left, b.left, f),
|
|
|
|
|
AndroidUtilities.lerp(a.top, b.top, f),
|
|
|
|
|
AndroidUtilities.lerp(a.right, b.right, f),
|
|
|
|
|
AndroidUtilities.lerp(a.bottom, b.bottom, f)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void lerp(Rect a, Rect b, float f, Rect to) {
|
|
|
|
|
if (to != null) {
|
|
|
|
|
to.set(
|
|
|
|
|
AndroidUtilities.lerp(a.left, b.left, f),
|
|
|
|
|
AndroidUtilities.lerp(a.top, b.top, f),
|
|
|
|
|
AndroidUtilities.lerp(a.right, b.right, f),
|
|
|
|
|
AndroidUtilities.lerp(a.bottom, b.bottom, f)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-21 04:51:00 +02:00
|
|
|
|
public static float computeDampingRatio(float tension /* stiffness */, float friction /* damping */, float mass) {
|
|
|
|
|
return friction / (2f * (float) Math.sqrt(mass * tension));
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
private static WeakReference<BaseFragment> flagSecureFragment;
|
|
|
|
|
|
|
|
|
|
public static boolean hasFlagSecureFragment() {
|
|
|
|
|
return flagSecureFragment != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setFlagSecure(BaseFragment parentFragment, boolean set) {
|
|
|
|
|
if (parentFragment == null || parentFragment.getParentActivity() == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (set) {
|
|
|
|
|
try {
|
|
|
|
|
parentFragment.getParentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
|
|
|
|
|
flagSecureFragment = new WeakReference<>(parentFragment);
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
} else if (flagSecureFragment != null && flagSecureFragment.get() == parentFragment) {
|
|
|
|
|
try {
|
|
|
|
|
parentFragment.getParentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
flagSecureFragment = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-01 14:00:45 +01:00
|
|
|
|
private static final HashMap<Window, ArrayList<Long>> flagSecureReasons = new HashMap<>();
|
|
|
|
|
// Sets FLAG_SECURE to true, until it gets unregistered (when returned callback is run)
|
|
|
|
|
// Useful for having multiple reasons to have this flag on.
|
|
|
|
|
public static Runnable registerFlagSecure(Window window) {
|
|
|
|
|
final long reasonId = (long) (Math.random() * 999999999);
|
|
|
|
|
final ArrayList<Long> reasonIds;
|
|
|
|
|
if (flagSecureReasons.containsKey(window)) {
|
|
|
|
|
reasonIds = flagSecureReasons.get(window);
|
|
|
|
|
} else {
|
|
|
|
|
reasonIds = new ArrayList<>();
|
|
|
|
|
flagSecureReasons.put(window, reasonIds);
|
|
|
|
|
}
|
|
|
|
|
reasonIds.add(reasonId);
|
|
|
|
|
updateFlagSecure(window);
|
|
|
|
|
return () -> {
|
|
|
|
|
reasonIds.remove(reasonId);
|
|
|
|
|
updateFlagSecure(window);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
private static void updateFlagSecure(Window window) {
|
|
|
|
|
if (Build.VERSION.SDK_INT >= 23) {
|
|
|
|
|
if (window == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
final boolean value = flagSecureReasons.containsKey(window) && flagSecureReasons.get(window).size() > 0;
|
|
|
|
|
try {
|
|
|
|
|
if (value) {
|
2022-03-20 21:22:37 +01:00
|
|
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
2022-02-01 14:00:45 +01:00
|
|
|
|
} else {
|
|
|
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception ignore) {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-31 14:08:08 +01:00
|
|
|
|
public static void openSharing(BaseFragment fragment, String url) {
|
|
|
|
|
if (fragment == null || fragment.getParentActivity() == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
fragment.showDialog(new ShareAlert(fragment.getParentActivity(), null, url, false, url, false));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static boolean allowScreenCapture() {
|
|
|
|
|
return SharedConfig.passcodeHash.length() == 0 || SharedConfig.allowScreenCapture;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static File getSharingDirectory() {
|
|
|
|
|
return new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), "sharing/");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static String getCertificateSHA256Fingerprint() {
|
|
|
|
|
PackageManager pm = ApplicationLoader.applicationContext.getPackageManager();
|
|
|
|
|
String packageName = ApplicationLoader.applicationContext.getPackageName();
|
|
|
|
|
try {
|
|
|
|
|
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
|
|
|
|
Signature[] signatures = packageInfo.signatures;
|
|
|
|
|
byte[] cert = signatures[0].toByteArray();
|
|
|
|
|
InputStream input = new ByteArrayInputStream(cert);
|
|
|
|
|
CertificateFactory cf = CertificateFactory.getInstance("X509");
|
|
|
|
|
X509Certificate c = (X509Certificate) cf.generateCertificate(input);
|
|
|
|
|
return Utilities.bytesToHex(Utilities.computeSHA256(c.getEncoded()));
|
|
|
|
|
} catch (Throwable ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-09 15:17:32 +02:00
|
|
|
|
private static char[] characters = new char[] {' ', ' ', '!', '"', '#', '%', '&', '\'', '(', ')', '*', ',', '-', '.', '/', ':', ';', '?', '@', '[', '\\', ']', '_', '{', '}', '¡', '§', '«', '¶', '·', '»', '¿', ';', '·', '՚', '՛', '՜', '՝', '՞', '՟', '։', '֊', '־', '׀', '׃', '׆', '׳', '״', '؉', '؊', '،', '؍', '؛', '؞', '؟', '٪', '٫', '٬', '٭', '۔', '܀', '܁', '܂', '܃', '܄', '܅', '܆', '܇', '܈', '܉', '܊', '܋', '܌', '܍', '߷', '߸', '߹', '࠰', '࠱', '࠲', '࠳', '࠴', '࠵', '࠶', '࠷', '࠸', '࠹', '࠺', '࠻', '࠼', '࠽', '࠾', '࡞', '।', '॥', '॰', '৽', '੶', '૰', '౷', '಄', '෴', '๏', '๚', '๛', '༄', '༅', '༆', '༇', '༈', '༉', '༊', '་', '༌', '།', '༎', '༏', '༐', '༑', '༒', '༔', '༺', '༻', '༼', '༽', '྅', '࿐', '࿑', '࿒', '࿓', '࿔', '࿙', '࿚', '၊', '။', '၌', '၍', '၎', '၏', '჻', '፠', '፡', '።', '፣', '፤', '፥', '፦', '፧', '፨', '᐀', '᙮', '᚛', '᚜', '᛫', '᛬', '᛭', '᜵', '᜶', '។', '៕', '៖', '៘', '៙', '៚', '᠀', '᠁', '᠂', '᠃', '᠄', '᠅', '᠆', '᠇', '᠈', '᠉', '᠊', '᥄', '᥅', '᨞', '᨟', '᪠', '᪡', '᪢', '᪣', '᪤', '᪥', '᪦', '᪨', '᪩', '᪪', '᪫', '᪬', '᪭', '᭚', '᭛', '᭜', '᭝', '᭞', '᭟', '᭠', '᯼', '᯽', '᯾', '᯿', '᰻', '᰼', '᰽', '᰾', '᰿', '᱾', '᱿', '᳀', '᳁', '᳂', '᳃', '᳄', '᳅', '᳆', '᳇', '᳓', '‐', '‑', '‒', '–', '—', '―', '‖', '‗', '‘', '’', '‚', '‛', '“', '”', '„', '‟', '†', '‡', '•', '‣', '․', '‥', '…', '‧', '‰', '‱', '′', '″', '‴', '‵', '‶', '‷', '‸', '‹', '›', '※', '‼', '‽', '‾', '‿', '⁀', '⁁', '⁂', '⁃', '⁅', '⁆', '⁇', '⁈', '⁉', '⁊', '⁋', '⁌', '⁍', '⁎', '⁏', '⁐', '⁑', '⁓', '⁔', '⁕', '⁖', '⁗', '⁘', '⁙', '⁚', '⁛', '⁜', '⁝', '⁞', '⁽', '⁾', '₍', '₎', '⌈', '⌉', '⌊', '⌋', '〈', '〉', '❨', '❩', '❪', '❫', '❬', '❭', '❮', '❯', '❰', '❱', '❲', '❳', '❴', '❵', '⟅', '⟆', '⟦', '⟧', '⟨', '⟩', '⟪', '⟫', '⟬', '⟭', '⟮', '⟯', '⦃', '⦄', '⦅', '⦆', '⦇', '⦈', '⦉', '⦊', '⦋', '⦌', '⦍', '⦎', '⦏', '⦐', '⦑', '⦒', '⦓', '⦔', '⦕', '⦖', '⦗', '⦘', '⧘', '⧙', '⧚', '⧛', '⧼', '⧽', '⳹', '⳺', '⳻', '⳼', '⳾', '⳿', '⵰', '⸀', '⸁', '⸂', '⸃', '⸄', '⸅', '⸆', '⸇', '⸈', '⸉', '⸊', '⸋', '⸌', '⸍', '⸎', '⸏', '⸐', '⸑', '⸒', '⸓', '⸔', '⸕', '⸖', '⸗', '⸘', '⸙', '⸚', '⸛', '⸜', '⸝', '⸞', '⸟', '⸠', '⸡', '⸢', '⸣', '⸤', '⸥', '⸦', '⸧', '⸨', '⸩', '⸪', '⸫', '⸬', '⸭', '⸮', '⸰', '⸱', '⸲', '⸳', '⸴', '⸵', '⸶', '⸷', '⸸', '⸹', '⸺', '⸻', '⸼', '⸽', '⸾', '⸿', '⹀', '⹁', '⹂', '⹃', '⹄', '⹅', '⹆', '⹇', '⹈', '⹉', '⹊', '⹋', '⹌', '⹍', '⹎', '⹏', '、', '。', '〃', '〈', '〉', '《', '》', '「', '」', '『', '』', '【', '】', '〔', '〕', '〖', '〗', '〘', '〙', '〚', '〛', '〜', '〝', '〞', '〟', '〰', '〽', '゠', '・', '꓾', '꓿', '꘍', '꘎', '꘏', '꙳', '꙾', '꛲', '꛳', '꛴', '꛵', '꛶', '꛷', '꡴', '꡵', '꡶', '꡷', '꣎', '꣏', '꣸', '꣹', '꣺', '꣼', '꤮', '꤯', '꥟', '꧁', '꧂', '꧃', '꧄', '꧅', '꧆', '꧇', '꧈', '꧉', '꧊', '꧋', '꧌', '꧍', '꧞', '꧟', '꩜', '꩝', '꩞', '꩟', '꫞', '꫟', '꫰', '꫱', '꯫', '﴾', '﴿', '︐', '︑', '︒', '︓', '︔', '︕', '︖', '︗', '︘', '︙', '︰', '︱', '︲', '︳', '︴', '︵', '︶', '︷', '︸', '︹', '︺', '︻', '︼', '︽', '︾', '︿', '﹀', '﹁', '﹂', '﹃', '﹄', '﹅', '﹆', '﹇', '﹈', '﹉', '﹊', '﹋', '﹌', '﹍', '﹎', '﹏', '﹐', '﹑', '﹒', '﹔', '﹕', '﹖', '﹗', '﹘', '﹙', '﹚', '﹛', '﹜', '﹝', '﹞', '﹟', '﹠', '﹡', '﹣', '﹨', '﹪', '﹫', '!', '"', '#', '%', '&', ''', '(', ')', '*', ',',
|
2019-12-31 14:08:08 +01:00
|
|
|
|
//private static String[] longCharacters = new String[] {"𐄀", "𐄁", "𐄂", "𐎟", "𐏐", "𐕯", "𐡗", "𐤟", "𐤿", "𐩐", "𐩑", "𐩒", "𐩓", "𐩔", "𐩕", "𐩖", "𐩗", "𐩘", "𐩿", "𐫰", "𐫱", "𐫲", "𐫳", "𐫴", "𐫵", "𐫶", "𐬹", "𐬺", "𐬻", "𐬼", "𐬽", "𐬾", "𐬿", "𐮙", "𐮚", "𐮛", "𐮜", "𐽕", "𐽖", "𐽗", "𐽘", "𐽙", "𑁇", "𑁈", "𑁉", "𑁊", "𑁋", "𑁌", "𑁍", "𑂻", "𑂼", "𑂾", "𑂿", "𑃀", "𑃁", "𑅀", "𑅁", "𑅂", "𑅃", "𑅴", "𑅵", "𑇅", "𑇆", "𑇇", "𑇈", "𑇍", "𑇛", "𑇝", "𑇞", "𑇟", "𑈸", "𑈹", "𑈺", "𑈻", "𑈼", "𑈽", "𑊩", "𑑋", "𑑌", "𑑍", "𑑎", "𑑏", "𑑛", "𑑝", "𑓆", "𑗁", "𑗂", "𑗃", "𑗄", "𑗅", "𑗆", "𑗇", "𑗈", "𑗉", "𑗊", "𑗋", "𑗌", "𑗍", "𑗎", "𑗏", "𑗐", "𑗑", "𑗒", "𑗓", "𑗔", "𑗕", "𑗖", "𑗗", "𑙁", "𑙂", "𑙃", "𑙠", "𑙡", "𑙢", "𑙣", "𑙤", "𑙥", "𑙦", "𑙧", "𑙨", "𑙩", "𑙪", "𑙫", "𑙬", "𑜼", "𑜽", "𑜾", "𑠻", "𑧢", "𑨿", "𑩀", "𑩁", "𑩂", "𑩃", "𑩄", "𑩅", "𑩆", "𑪚", "𑪛", "𑪜", "𑪞", "𑪟", "𑪠", "𑪡", "𑪢", "𑱁", "𑱂", "𑱃", "𑱄", "𑱅", "𑱰", "𑱱", "𑻷", "𑻸", "𑿿", "𒑰", "𒑱", "𒑲", "𒑳", "𒑴", "𖩮", "𖩯", "𖫵", "𖬷", "𖬸", "𖬹", "𖬺", "𖬻", "𖭄", "𖺗", "𖺘", "𖺙", "𖺚", "𖿢", "𛲟", "𝪇", "𝪈", "𝪉", "𝪊", "𝪋", "𞥞", "𞥟"};
|
|
|
|
|
private static HashSet<Character> charactersMap;
|
|
|
|
|
|
|
|
|
|
public static boolean isPunctuationCharacter(char ch) {
|
|
|
|
|
if (charactersMap == null) {
|
|
|
|
|
charactersMap = new HashSet<>();
|
|
|
|
|
for (int a = 0; a < characters.length; a++) {
|
|
|
|
|
charactersMap.add(characters[a]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//int len = longCharacters[0].length();
|
|
|
|
|
return charactersMap.contains(ch);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getColorDistance(int color1, int color2) {
|
|
|
|
|
int r1 = Color.red(color1);
|
|
|
|
|
int g1 = Color.green(color1);
|
|
|
|
|
int b1 = Color.blue(color1);
|
|
|
|
|
|
|
|
|
|
int r2 = Color.red(color2);
|
|
|
|
|
int g2 = Color.green(color2);
|
|
|
|
|
int b2 = Color.blue(color2);
|
|
|
|
|
|
|
|
|
|
int rMean = (r1 + r2) / 2;
|
|
|
|
|
int r = r1 - r2;
|
|
|
|
|
int g = g1 - g2;
|
|
|
|
|
int b = b1 - b2;
|
|
|
|
|
return (((512 + rMean) * r * r) >> 8) + (4 * g * g) + (((767 - rMean) * b * b) >> 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int getAverageColor(int color1, int color2) {
|
|
|
|
|
int r1 = Color.red(color1);
|
|
|
|
|
int r2 = Color.red(color2);
|
|
|
|
|
int g1 = Color.green(color1);
|
|
|
|
|
int g2 = Color.green(color2);
|
|
|
|
|
int b1 = Color.blue(color1);
|
|
|
|
|
int b2 = Color.blue(color2);
|
|
|
|
|
return Color.argb(255, (r1 / 2 + r2 / 2), (g1 / 2 + g2 / 2), (b1 / 2 + b2 / 2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setLightStatusBar(Window window, boolean enable) {
|
2022-03-11 17:49:54 +01:00
|
|
|
|
setLightStatusBar(window, enable, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setLightStatusBar(Window window, boolean enable, boolean forceTransparentStatusbar) {
|
2019-12-31 14:08:08 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
|
final View decorView = window.getDecorView();
|
|
|
|
|
int flags = decorView.getSystemUiVisibility();
|
|
|
|
|
if (enable) {
|
|
|
|
|
if ((flags & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) == 0) {
|
|
|
|
|
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
|
|
|
|
decorView.setSystemUiVisibility(flags);
|
2022-03-11 17:49:54 +01:00
|
|
|
|
}
|
|
|
|
|
if (!SharedConfig.noStatusBar && !forceTransparentStatusbar) {
|
|
|
|
|
window.setStatusBarColor(LIGHT_STATUS_BAR_OVERLAY);
|
|
|
|
|
} else {
|
|
|
|
|
window.setStatusBarColor(Color.TRANSPARENT);
|
2019-12-31 14:08:08 +01:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((flags & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0) {
|
|
|
|
|
flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
|
|
|
|
|
decorView.setSystemUiVisibility(flags);
|
2022-03-11 17:49:54 +01:00
|
|
|
|
}
|
|
|
|
|
if (!SharedConfig.noStatusBar && !forceTransparentStatusbar) {
|
|
|
|
|
window.setStatusBarColor(DARK_STATUS_BAR_OVERLAY);
|
|
|
|
|
} else {
|
|
|
|
|
window.setStatusBarColor(Color.TRANSPARENT);
|
2019-12-31 14:08:08 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-11 17:49:54 +01:00
|
|
|
|
public static boolean getLightNavigationBar(Window window) {
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
|
final View decorView = window.getDecorView();
|
|
|
|
|
int flags = decorView.getSystemUiVisibility();
|
|
|
|
|
return (flags & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) > 0;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-16 16:43:17 +02:00
|
|
|
|
public static void setLightNavigationBar(View view, boolean enable) {
|
|
|
|
|
if (view != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
|
int flags = view.getSystemUiVisibility();
|
2019-12-31 14:08:08 +01:00
|
|
|
|
if (enable) {
|
|
|
|
|
flags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
|
|
|
|
} else {
|
|
|
|
|
flags &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
|
|
|
|
|
}
|
2022-04-16 16:43:17 +02:00
|
|
|
|
view.setSystemUiVisibility(flags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setLightNavigationBar(Window window, boolean enable) {
|
|
|
|
|
if (window != null) {
|
|
|
|
|
setLightNavigationBar(window.getDecorView(), enable);
|
2019-12-31 14:08:08 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-24 11:21:58 +02:00
|
|
|
|
|
2022-03-20 21:22:37 +01:00
|
|
|
|
private static HashMap<Window, ValueAnimator> navigationBarColorAnimators;
|
2022-04-16 16:43:17 +02:00
|
|
|
|
public interface IntColorCallback {
|
|
|
|
|
public void run(int color);
|
|
|
|
|
}
|
2022-03-20 21:22:37 +01:00
|
|
|
|
|
|
|
|
|
public static void setNavigationBarColor(Window window, int color) {
|
|
|
|
|
setNavigationBarColor(window, color, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setNavigationBarColor(Window window, int color, boolean animated) {
|
2022-04-16 16:43:17 +02:00
|
|
|
|
setNavigationBarColor(window, color, animated, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void setNavigationBarColor(Window window, int color, boolean animated, IntColorCallback onUpdate) {
|
2022-03-20 21:22:37 +01:00
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
|
|
|
if (navigationBarColorAnimators != null) {
|
|
|
|
|
ValueAnimator animator = navigationBarColorAnimators.get(window);
|
|
|
|
|
if (animator != null) {
|
|
|
|
|
animator.cancel();
|
|
|
|
|
navigationBarColorAnimators.remove(window);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!animated) {
|
2022-04-16 16:43:17 +02:00
|
|
|
|
if (onUpdate != null) {
|
|
|
|
|
onUpdate.run(color);
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
window.setNavigationBarColor(color);
|
|
|
|
|
} catch (Exception ignore) {}
|
2022-03-20 21:22:37 +01:00
|
|
|
|
} else {
|
|
|
|
|
ValueAnimator animator = ValueAnimator.ofArgb(window.getNavigationBarColor(), color);
|
2022-04-16 16:43:17 +02:00
|
|
|
|
animator.addUpdateListener(a -> {
|
|
|
|
|
int tcolor = (int) a.getAnimatedValue();
|
|
|
|
|
if (onUpdate != null) {
|
|
|
|
|
onUpdate.run(tcolor);
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
window.setNavigationBarColor(tcolor);
|
|
|
|
|
} catch (Exception ignore) {}
|
|
|
|
|
});
|
2022-03-20 21:22:37 +01:00
|
|
|
|
animator.addListener(new AnimatorListenerAdapter() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onAnimationEnd(Animator animation) {
|
|
|
|
|
if (navigationBarColorAnimators != null) {
|
|
|
|
|
navigationBarColorAnimators.remove(window);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
animator.setDuration(200);
|
|
|
|
|
animator.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
|
|
|
animator.start();
|
|
|
|
|
if (navigationBarColorAnimators == null) {
|
|
|
|
|
navigationBarColorAnimators = new HashMap<>();
|
|
|
|
|
}
|
|
|
|
|
navigationBarColorAnimators.put(window, animator);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-23 12:53:38 +01:00
|
|
|
|
public static boolean checkHostForPunycode(String url) {
|
2021-12-30 11:52:40 +01:00
|
|
|
|
if (url == null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-04-24 11:21:58 +02:00
|
|
|
|
boolean hasLatin = false;
|
|
|
|
|
boolean hasNonLatin = false;
|
|
|
|
|
try {
|
|
|
|
|
for (int a = 0, N = url.length(); a < N; a++) {
|
|
|
|
|
char ch = url.charAt(a);
|
|
|
|
|
if (ch == '.' || ch == '-' || ch == '/' || ch == '+' || ch >= '0' && ch <= '9') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-05-01 04:08:26 +02:00
|
|
|
|
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
|
2020-04-24 11:21:58 +02:00
|
|
|
|
hasLatin = true;
|
|
|
|
|
} else {
|
|
|
|
|
hasNonLatin = true;
|
|
|
|
|
}
|
|
|
|
|
if (hasLatin && hasNonLatin) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
return hasLatin && hasNonLatin;
|
|
|
|
|
}
|
2020-07-26 10:03:38 +02:00
|
|
|
|
|
2021-02-23 12:53:38 +01:00
|
|
|
|
public static boolean shouldShowUrlInAlert(String url) {
|
|
|
|
|
try {
|
|
|
|
|
Uri uri = Uri.parse(url);
|
|
|
|
|
url = uri.getHost();
|
|
|
|
|
return checkHostForPunycode(url);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-26 10:03:38 +02:00
|
|
|
|
public static void scrollToFragmentRow(ActionBarLayout parentLayout, String rowName) {
|
|
|
|
|
if (parentLayout == null || rowName == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
BaseFragment openingFragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1);
|
|
|
|
|
try {
|
|
|
|
|
Field listViewField = openingFragment.getClass().getDeclaredField("listView");
|
|
|
|
|
listViewField.setAccessible(true);
|
|
|
|
|
RecyclerListView listView = (RecyclerListView) listViewField.get(openingFragment);
|
|
|
|
|
RecyclerListView.IntReturnCallback callback = () -> {
|
|
|
|
|
int position = -1;
|
|
|
|
|
try {
|
|
|
|
|
Field rowField = openingFragment.getClass().getDeclaredField(rowName);
|
|
|
|
|
rowField.setAccessible(true);
|
|
|
|
|
LinearLayoutManager layoutManager = (LinearLayoutManager) listView.getLayoutManager();
|
|
|
|
|
position = rowField.getInt(openingFragment);
|
|
|
|
|
layoutManager.scrollToPositionWithOffset(position, AndroidUtilities.dp(60));
|
|
|
|
|
rowField.setAccessible(false);
|
|
|
|
|
return position;
|
|
|
|
|
} catch (Throwable ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return position;
|
|
|
|
|
};
|
|
|
|
|
listView.highlightRow(callback);
|
|
|
|
|
listViewField.setAccessible(false);
|
|
|
|
|
} catch (Throwable ignore) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-14 18:58:22 +02:00
|
|
|
|
|
|
|
|
|
public static boolean checkInlinePermissions(Context context) {
|
2022-03-11 17:49:54 +01:00
|
|
|
|
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(context);
|
2020-08-14 18:58:22 +02:00
|
|
|
|
}
|
2021-01-28 15:15:51 +01:00
|
|
|
|
|
|
|
|
|
public static void updateVisibleRows(RecyclerListView listView) {
|
|
|
|
|
if (listView == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RecyclerView.Adapter adapter = listView.getAdapter();
|
|
|
|
|
if (adapter == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < listView.getChildCount(); i++) {
|
|
|
|
|
View child = listView.getChildAt(i);
|
|
|
|
|
int p = listView.getChildAdapterPosition(child);
|
|
|
|
|
if (p >= 0) {
|
|
|
|
|
RecyclerView.ViewHolder holder = listView.getChildViewHolder(child);
|
|
|
|
|
if (holder == null || holder.shouldIgnore()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
adapter.onBindViewHolder(holder, p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-19 11:25:58 +01:00
|
|
|
|
|
2022-06-21 04:51:00 +02:00
|
|
|
|
public static void updateImageViewImageAnimated(ImageView imageView, int newIcon) {
|
|
|
|
|
updateImageViewImageAnimated(imageView, ContextCompat.getDrawable(imageView.getContext(), newIcon));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void updateImageViewImageAnimated(ImageView imageView, Drawable newIcon) {
|
|
|
|
|
ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration(150);
|
|
|
|
|
AtomicBoolean changed = new AtomicBoolean();
|
|
|
|
|
animator.addUpdateListener(animation -> {
|
|
|
|
|
float val = (float) animation.getAnimatedValue();
|
|
|
|
|
float scale = 0.5f + Math.abs(val - 0.5f);
|
|
|
|
|
imageView.setScaleX(scale);
|
|
|
|
|
imageView.setScaleY(scale);
|
|
|
|
|
if (val >= 0.5f && !changed.get()) {
|
|
|
|
|
changed.set(true);
|
|
|
|
|
imageView.setImageDrawable(newIcon);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
animator.start();
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-19 11:25:58 +01:00
|
|
|
|
public static void updateViewVisibilityAnimated(View view, boolean show) {
|
|
|
|
|
updateViewVisibilityAnimated(view, show, 1f, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void updateViewVisibilityAnimated(View view, boolean show, float scaleFactor, boolean animated) {
|
2022-06-21 04:51:00 +02:00
|
|
|
|
if (view == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-03-19 11:25:58 +01:00
|
|
|
|
if (view.getParent() == null) {
|
|
|
|
|
animated = false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-31 21:06:39 +02:00
|
|
|
|
if (!animated) {
|
2021-04-14 03:44:46 +02:00
|
|
|
|
view.animate().setListener(null).cancel();
|
|
|
|
|
view.setVisibility(show ? View.VISIBLE : View.GONE);
|
|
|
|
|
view.setTag(show ? 1 : null);
|
|
|
|
|
view.setAlpha(1f);
|
|
|
|
|
view.setScaleX(1f);
|
|
|
|
|
view.setScaleY(1f);
|
2021-08-31 21:06:39 +02:00
|
|
|
|
} else if (show && view.getTag() == null) {
|
|
|
|
|
view.animate().setListener(null).cancel();
|
|
|
|
|
if (view.getVisibility() != View.VISIBLE) {
|
|
|
|
|
view.setVisibility(View.VISIBLE);
|
|
|
|
|
view.setAlpha(0f);
|
|
|
|
|
view.setScaleX(scaleFactor);
|
|
|
|
|
view.setScaleY(scaleFactor);
|
|
|
|
|
}
|
|
|
|
|
view.animate().alpha(1f).scaleY(1f).scaleX(1f).setDuration(150).start();
|
|
|
|
|
view.setTag(1);
|
|
|
|
|
} else if (!show && view.getTag() != null) {
|
|
|
|
|
view.animate().setListener(null).cancel();
|
|
|
|
|
view.animate().alpha(0).scaleY(scaleFactor).scaleX(scaleFactor).setListener(new HideViewAfterAnimation(view)).setDuration(150).start();
|
|
|
|
|
view.setTag(null);
|
2021-03-19 11:25:58 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-09-20 07:54:41 +02:00
|
|
|
|
|
|
|
|
|
public static long getPrefIntOrLong(SharedPreferences preferences, String key, long defaultValue) {
|
|
|
|
|
try {
|
|
|
|
|
return preferences.getLong(key, defaultValue);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return preferences.getInt(key, (int) defaultValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-12-30 11:52:40 +01:00
|
|
|
|
|
|
|
|
|
public static Bitmap getScaledBitmap(float w, float h, String path, String streamPath, int streamOffset) {
|
|
|
|
|
FileInputStream stream = null;
|
|
|
|
|
try {
|
|
|
|
|
BitmapFactory.Options options = new BitmapFactory.Options();
|
|
|
|
|
options.inJustDecodeBounds = true;
|
|
|
|
|
|
|
|
|
|
if (path != null) {
|
|
|
|
|
BitmapFactory.decodeFile(path, options);
|
|
|
|
|
} else {
|
|
|
|
|
stream = new FileInputStream(streamPath);
|
|
|
|
|
stream.getChannel().position(streamOffset);
|
|
|
|
|
BitmapFactory.decodeStream(stream, null, options);
|
|
|
|
|
}
|
|
|
|
|
if (options.outWidth > 0 && options.outHeight > 0) {
|
|
|
|
|
if (w > h && options.outWidth < options.outHeight) {
|
|
|
|
|
float temp = w;
|
|
|
|
|
w = h;
|
|
|
|
|
h = temp;
|
|
|
|
|
}
|
|
|
|
|
float scale = Math.min(options.outWidth / w, options.outHeight / h);
|
|
|
|
|
options.inSampleSize = 1;
|
|
|
|
|
if (scale > 1.0f) {
|
|
|
|
|
do {
|
|
|
|
|
options.inSampleSize *= 2;
|
|
|
|
|
} while (options.inSampleSize < scale);
|
|
|
|
|
}
|
|
|
|
|
options.inJustDecodeBounds = false;
|
|
|
|
|
Bitmap wallpaper;
|
|
|
|
|
if (path != null) {
|
|
|
|
|
wallpaper = BitmapFactory.decodeFile(path, options);
|
|
|
|
|
} else {
|
|
|
|
|
stream.getChannel().position(streamOffset);
|
|
|
|
|
wallpaper = BitmapFactory.decodeStream(stream, null, options);
|
|
|
|
|
}
|
|
|
|
|
return wallpaper;
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
} finally {
|
|
|
|
|
try {
|
|
|
|
|
if (stream != null) {
|
|
|
|
|
stream.close();
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e2) {
|
|
|
|
|
FileLog.e(e2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Uri getBitmapShareUri(Bitmap bitmap, String fileName, Bitmap.CompressFormat format) {
|
|
|
|
|
File cachePath = AndroidUtilities.getCacheDir();
|
|
|
|
|
if (!cachePath.isDirectory()) {
|
|
|
|
|
try {
|
|
|
|
|
cachePath.mkdirs();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
FileLog.e(e);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
File file = new File(cachePath, fileName);
|
|
|
|
|
try (FileOutputStream out = new FileOutputStream(file)) {
|
|
|
|
|
bitmap.compress(format, 100, out);
|
|
|
|
|
out.close();
|
|
|
|
|
return FileProvider.getUriForFile(ApplicationLoader.applicationContext, BuildConfig.APPLICATION_ID + ".provider", file);
|
2022-04-16 16:43:17 +02:00
|
|
|
|
} catch (Exception e) {
|
2021-12-30 11:52:40 +01:00
|
|
|
|
FileLog.e(e);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2022-03-13 02:58:00 +01:00
|
|
|
|
|
|
|
|
|
public static boolean isNumeric(String str) {
|
|
|
|
|
try {
|
|
|
|
|
Double.parseDouble(str);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-21 04:51:00 +02:00
|
|
|
|
|
|
|
|
|
public static boolean isAccessibilityScreenReaderEnabled() {
|
|
|
|
|
return false;
|
|
|
|
|
// try {
|
|
|
|
|
// AccessibilityManager am = (AccessibilityManager) ApplicationLoader.applicationContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
|
|
|
|
|
// return (am != null && am.isEnabled() && !am.isTouchExplorationEnabled());
|
|
|
|
|
// } catch (Exception ignroe) {
|
|
|
|
|
// return false;
|
|
|
|
|
// }
|
|
|
|
|
}
|
2014-07-03 00:39:05 +02:00
|
|
|
|
}
|