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 ;
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 ;
2022-09-21 16:20:30 +02:00
import android.os.Bundle ;
2014-07-03 00:39:05 +02:00
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 ;
2022-11-05 13:34:47 +01:00
import android.system.ErrnoException ;
import android.system.OsConstants ;
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-11-05 13:34:47 +01:00
import android.text.style.CharacterStyle ;
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 ;
2022-12-30 13:32:20 +01:00
import android.view.ViewPropertyAnimator ;
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 ;
2022-12-30 13:32:20 +01:00
import android.view.inspector.WindowInspector ;
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-09-16 20:48:21 +02:00
import androidx.core.graphics.ColorUtils ;
2022-08-12 17:23:51 +02:00
import androidx.core.math.MathUtils ;
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 ;
2022-08-12 17:23:51 +02:00
import org.telegram.messenger.utils.CustomHtml ;
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 ;
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 ;
2022-11-05 13:34:47 +01:00
import org.telegram.ui.ActionBar.INavigationLayout ;
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-12-30 13:32:20 +01:00
import org.telegram.ui.ChatActivity ;
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-12-30 13:32:20 +01:00
import org.telegram.ui.Components.Bulletin ;
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 ;
2022-09-16 20:48:21 +02:00
import org.telegram.ui.Components.URLSpanReplacement ;
2022-12-30 13:32:20 +01:00
import org.telegram.ui.Components.UndoView ;
import org.telegram.ui.LaunchActivity ;
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 ;
2022-12-30 13:32:20 +01:00
import java.util.Arrays ;
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-11-05 13:34:47 +01:00
import java.util.Map ;
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-11-05 13:34:47 +01:00
public final static int REPLACING_TAG_TYPE_LINK = 0 ;
public final static int REPLACING_TAG_TYPE_BOLD = 1 ;
2022-06-21 04:51:00 +02:00
public final static String TYPEFACE_ROBOTO_MEDIUM = " fonts/rmedium.ttf " ;
2022-12-30 13:32:20 +01:00
public final static String TYPEFACE_ROBOTO_MEDIUM_ITALIC = " fonts/rmediumitalic.ttf " ;
public final static String TYPEFACE_ROBOTO_MONO = " fonts/rmono.ttf " ;
public final static String TYPEFACE_MERRIWEATHER_BOLD = " fonts/mw_bold.ttf " ;
public final static String TYPEFACE_COURIER_NEW_BOLD = " fonts/courier_new_bold.ttf " ;
2022-06-21 04:51:00 +02:00
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
2022-09-16 20:48:21 +02:00
private static Boolean isTablet = null , wasTablet = 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 ) {
2022-11-05 13:34:47 +01:00
return replaceSingleTag ( str , null , 0 , runnable ) ;
2022-09-16 20:48:21 +02:00
}
2022-11-05 13:34:47 +01:00
public static CharSequence replaceSingleTag ( String str , String colorKey , int type , Runnable runnable ) {
2022-04-16 16:43:17 +02:00
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 ) {
2022-11-05 13:34:47 +01:00
if ( type = = REPLACING_TAG_TYPE_LINK ) {
spannableStringBuilder . setSpan ( new ClickableSpan ( ) {
@Override
public void updateDrawState ( @NonNull TextPaint ds ) {
super . updateDrawState ( ds ) ;
ds . setUnderlineText ( false ) ;
if ( colorKey ! = null ) {
ds . setColor ( Theme . getColor ( colorKey ) ) ;
}
2022-09-16 20:48:21 +02:00
}
2022-04-16 16:43:17 +02:00
2022-11-05 13:34:47 +01:00
@Override
public void onClick ( @NonNull View view ) {
if ( runnable ! = null ) {
runnable . run ( ) ;
}
2022-08-12 17:23:51 +02:00
}
2022-11-05 13:34:47 +01:00
} , index , index + len , 0 ) ;
} else {
spannableStringBuilder . setSpan ( new CharacterStyle ( ) {
@Override
public void updateDrawState ( TextPaint textPaint ) {
textPaint . setTypeface ( AndroidUtilities . getTypeface ( " fonts/rmedium.ttf " ) ) ;
int wasAlpha = textPaint . getAlpha ( ) ;
textPaint . setColor ( Theme . getColor ( Theme . key_windowBackgroundWhiteBlueText ) ) ;
textPaint . setAlpha ( wasAlpha ) ;
}
} , index , index + len , 0 ) ;
}
2022-04-16 16:43:17 +02:00
}
return spannableStringBuilder ;
}
2022-12-06 20:13:44 +01:00
public static void recycleBitmaps ( List < Bitmap > bitmapToRecycle ) {
2022-06-21 04:51:00 +02:00
if ( bitmapToRecycle ! = null & & ! bitmapToRecycle . isEmpty ( ) ) {
2022-08-12 17:23:51 +02:00
AndroidUtilities . runOnUIThread ( ( ) - > Utilities . globalQueue . postRunnable ( ( ) - > {
2022-06-21 04:51:00 +02:00
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 ) ;
}
}
}
2022-12-31 11:47:53 +01:00
} ) , Build . VERSION . SDK_INT < = 23 ? 100 : 36 ) ;
2022-06-21 04:51:00 +02:00
}
}
2022-09-21 16:20:30 +02:00
public static void googleVoiceClientService_performAction ( Intent intent , boolean isVerified , Bundle options ) {
if ( ! isVerified ) {
return ;
}
AndroidUtilities . runOnUIThread ( ( ) - > {
try {
int currentAccount = UserConfig . selectedAccount ;
ApplicationLoader . postInitApplication ( ) ;
if ( AndroidUtilities . needShowPasscode ( ) | | SharedConfig . isWaitingForPasscodeEnter ) {
return ;
}
String text = intent . getStringExtra ( " android.intent.extra.TEXT " ) ;
if ( ! TextUtils . isEmpty ( text ) ) {
String contactUri = intent . getStringExtra ( " com.google.android.voicesearch.extra.RECIPIENT_CONTACT_URI " ) ;
String id = intent . getStringExtra ( " com.google.android.voicesearch.extra.RECIPIENT_CONTACT_CHAT_ID " ) ;
long uid = Long . parseLong ( id ) ;
TLRPC . User user = MessagesController . getInstance ( currentAccount ) . getUser ( uid ) ;
if ( user = = null ) {
user = MessagesStorage . getInstance ( currentAccount ) . getUserSync ( uid ) ;
if ( user ! = null ) {
MessagesController . getInstance ( currentAccount ) . putUser ( user , true ) ;
}
}
if ( user ! = null ) {
ContactsController . getInstance ( currentAccount ) . markAsContacted ( contactUri ) ;
SendMessagesHelper . getInstance ( currentAccount ) . sendMessage ( text , user . id , null , null , null , true , null , null , null , true , 0 , null , false ) ;
}
}
} catch ( Exception e ) {
FileLog . e ( e ) ;
}
} ) ;
}
2022-12-06 20:13:44 +01:00
public static void recycleBitmap ( Bitmap image ) {
recycleBitmaps ( Collections . singletonList ( image ) ) ;
}
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 ) {
2022-09-16 20:48:21 +02:00
return addLinks ( text , mask , internalOnly , true ) ;
}
public static boolean addLinks ( Spannable text , int mask , boolean internalOnly , boolean removeOldReplacements ) {
2020-10-30 11:26:29 +01:00
if ( text = = null | | containsUnsupportedCharacters ( text . toString ( ) ) | | mask = = 0 ) {
2019-12-31 14:08:08 +01:00
return false ;
}
2022-09-16 20:48:21 +02:00
URLSpan [ ] old = text . getSpans ( 0 , text . length ( ) , URLSpan . class ) ;
2019-12-31 14:08:08 +01:00
for ( int i = old . length - 1 ; i > = 0 ; i - - ) {
2022-09-16 20:48:21 +02:00
URLSpan o = old [ i ] ;
if ( ! ( o instanceof URLSpanReplacement ) | | removeOldReplacements ) {
text . removeSpan ( o ) ;
}
2019-12-31 14:08:08 +01:00
}
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 + + ) {
2022-09-16 20:48:21 +02:00
URLSpan o = oldSpans [ b ] ;
text . removeSpan ( o ) ;
if ( ! ( o instanceof URLSpanReplacement ) | | removeOldReplacements ) {
text . removeSpan ( o ) ;
}
2020-05-01 04:08:26 +02:00
}
}
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 ;
2022-09-16 20:48:21 +02:00
} else if ( name . contains ( " .zip " ) | | name . contains ( " .rar " ) | | name . contains ( " .ai " ) | | name . contains ( " .mp3 " ) | | name . contains ( " .mov " ) | | name . contains ( " .avi " ) ) {
2019-01-23 18:03:33 +01:00
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 ) {
2022-11-05 13:34:47 +01:00
if ( bitmap = = null ) {
return 0 ;
}
2020-02-13 19:26:53 +01:00
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 ;
2022-09-16 20:48:21 +02:00
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
2022-03-11 17:49:54 +01:00
} ) ) ;
}
2022-09-16 20:48:21 +02:00
2022-03-11 17:49:54 +01:00
public static void adjustBrightnessColorMatrix ( ColorMatrix colorMatrix , float brightness ) {
if ( colorMatrix = = null ) {
return ;
}
brightness * = 255 ;
2022-09-16 20:48:21 +02:00
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
2022-03-11 17:49:54 +01:00
} ) ) ;
}
2022-09-16 20:48:21 +02:00
2022-11-05 13:34:47 +01:00
public static void adjustHueColorMatrix ( ColorMatrix cm , float value ) {
value = cleanValue ( value , 180f ) / 180f * ( float ) Math . PI ;
if ( value = = 0 ) {
return ;
}
float cosVal = ( float ) Math . cos ( value ) ;
float sinVal = ( float ) Math . sin ( value ) ;
float lumR = 0 . 213f ;
float lumG = 0 . 715f ;
float lumB = 0 . 072f ;
float [ ] mat = new float [ ]
{
lumR + cosVal * ( 1 - lumR ) + sinVal * ( - lumR ) , lumG + cosVal * ( - lumG ) + sinVal * ( - lumG ) , lumB + cosVal * ( - lumB ) + sinVal * ( 1 - lumB ) , 0 , 0 ,
lumR + cosVal * ( - lumR ) + sinVal * ( 0 . 143f ) , lumG + cosVal * ( 1 - lumG ) + sinVal * ( 0 . 140f ) , lumB + cosVal * ( - lumB ) + sinVal * ( - 0 . 283f ) , 0 , 0 ,
lumR + cosVal * ( - lumR ) + sinVal * ( - ( 1 - lumR ) ) , lumG + cosVal * ( - lumG ) + sinVal * ( lumG ) , lumB + cosVal * ( 1 - lumB ) + sinVal * ( lumB ) , 0 , 0 ,
0f , 0f , 0f , 1f , 0f ,
0f , 0f , 0f , 0f , 1f } ;
cm . postConcat ( new ColorMatrix ( mat ) ) ;
}
protected static float cleanValue ( float p_val , float p_limit ) {
return Math . min ( p_limit , Math . max ( - p_limit , p_val ) ) ;
}
2022-03-11 17:49:54 +01:00
public static void multiplyBrightnessColorMatrix ( ColorMatrix colorMatrix , float v ) {
2022-02-15 21:18:49 +01:00
if ( colorMatrix = = null ) {
return ;
}
2022-09-16 20:48:21 +02: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
2022-03-11 17:49:54 +01:00
} ) ) ;
}
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
}
}
2022-08-12 17:23:51 +02:00
public static boolean isMapsInstalled ( BaseFragment fragment ) {
String pkg = ApplicationLoader . getMapsProvider ( ) . getMapsAppPackageName ( ) ;
2016-04-22 15:49:00 +02:00
try {
2022-08-12 17:23:51 +02:00
ApplicationLoader . applicationContext . getPackageManager ( ) . getApplicationInfo ( pkg , 0 ) ;
2016-04-22 15:49:00 +02:00
return true ;
} catch ( PackageManager . NameNotFoundException e ) {
if ( fragment . getParentActivity ( ) = = null ) {
return false ;
}
AlertDialog . Builder builder = new AlertDialog . Builder ( fragment . getParentActivity ( ) ) ;
2022-08-12 17:23:51 +02:00
builder . setMessage ( LocaleController . getString ( ApplicationLoader . getMapsProvider ( ) . getInstallMapsString ( ) ) ) ;
2019-01-23 18:03:33 +01:00
builder . setPositiveButton ( LocaleController . getString ( " OK " , R . string . OK ) , ( dialogInterface , i ) - > {
try {
2022-08-12 17:23:51 +02:00
Intent intent = new Intent ( Intent . ACTION_VIEW , Uri . parse ( " market://details?id= " + pkg ) ) ;
2019-01-23 18:03:33 +01:00
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 ) ;
2022-09-16 20:48:21 +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 = = '~' ;
}
2022-11-05 13:34:47 +01:00
public static boolean isTabletForce ( ) {
return ApplicationLoader . applicationContext ! = null & & ApplicationLoader . applicationContext . getResources ( ) . getBoolean ( R . bool . isTablet ) ;
}
2022-09-16 20:48:21 +02:00
public static boolean isTabletInternal ( ) {
2014-09-24 17:08:25 +02:00
if ( isTablet = = null ) {
2022-11-05 13:34:47 +01:00
isTablet = isTabletForce ( ) ;
2014-09-24 17:08:25 +02:00
}
return isTablet ;
2014-09-24 04:17:27 +02:00
}
2022-09-16 20:48:21 +02:00
public static void resetTabletFlag ( ) {
if ( wasTablet = = null ) {
wasTablet = isTabletInternal ( ) ;
}
isTablet = null ;
SharedConfig . updateTabletConfig ( ) ;
}
public static void resetWasTabletFlag ( ) {
wasTablet = null ;
}
public static Boolean getWasTablet ( ) {
return wasTablet ;
}
public static boolean isTablet ( ) {
return isTabletInternal ( ) & & ! SharedConfig . forceDisableTabletMode ;
}
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
2022-11-05 13:34:47 +01:00
public static void shakeView ( final View view ) {
2018-07-30 04:07:02 +02:00
if ( view = = null ) {
return ;
}
2022-11-05 13:34:47 +01:00
final float N = 4 ;
Object animator = view . getTag ( R . id . shake_animation ) ;
if ( animator instanceof ValueAnimator ) {
( ( ValueAnimator ) animator ) . cancel ( ) ;
2015-04-09 20:00:14 +02:00
}
2022-11-05 13:34:47 +01:00
ValueAnimator va = ValueAnimator . ofFloat ( 0 , 1 ) ;
va . addUpdateListener ( anm - > {
float x = ( float ) anm . getAnimatedValue ( ) ;
view . setTranslationX ( ( float ) ( ( 4 * x * ( 1 - x ) ) * Math . sin ( N * ( x * Math . PI ) ) * AndroidUtilities . dp ( N ) ) ) ;
} ) ;
va . 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 ) {
2022-11-05 13:34:47 +01:00
view . setTranslationX ( 0 ) ;
2015-04-09 20:00:14 +02:00
}
} ) ;
2022-11-05 13:34:47 +01:00
va . setDuration ( 300 ) ;
va . start ( ) ;
view . setTag ( R . id . shake_animation , va ) ;
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 ) ;
2022-11-05 13:34:47 +01:00
if ( view . getTag ( R . id . spring_tag ) ! = null ) {
( ( SpringAnimation ) view . getTag ( R . id . spring_tag ) ) . cancel ( ) ;
}
Float wasX = ( Float ) view . getTag ( R . id . spring_was_translation_x_tag ) ;
if ( wasX ! = null ) {
view . setTranslationX ( wasX ) ;
}
view . setTag ( R . id . spring_was_translation_x_tag , view . getTranslationX ( ) ) ;
float translationX = view . getTranslationX ( ) ;
SpringAnimation springAnimation = new SpringAnimation ( view , DynamicAnimation . TRANSLATION_X , translationX )
. setSpring ( new SpringForce ( translationX ) . setStiffness ( 600f ) )
2022-03-11 17:49:54 +01:00
. setStartVelocity ( - shift * 100 )
. addEndListener ( ( animation , canceled , value , velocity ) - > {
if ( endCallback ! = null ) endCallback . run ( ) ;
2022-11-05 13:34:47 +01:00
view . setTranslationX ( translationX ) ;
view . setTag ( R . id . spring_tag , null ) ;
view . setTag ( R . id . spring_was_translation_x_tag , null ) ;
} ) ;
view . setTag ( R . id . spring_tag , springAnimation ) ;
springAnimation . start ( ) ;
2022-03-11 17:49:54 +01:00
}
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
2021-12-07 14:02:02 +01:00
public static void appCenterLog ( Throwable e ) {
2022-09-21 16:20:30 +02:00
ApplicationLoader . appCenterLog ( e ) ;
2021-12-07 14:02:02 +01:00
}
2022-03-11 17:49:54 +01:00
public static boolean shouldShowClipboardToast ( ) {
2022-12-06 20:13:44 +01:00
return ( Build . VERSION . SDK_INT < Build . VERSION_CODES . S | | ! OneUIUtilities . hasBuiltInClipboardToasts ( ) ) & & Build . VERSION . SDK_INT < 32 /* TODO: Update to TIRAMISU when compileSdkVersion would be 32 */ ;
2022-03-11 17:49:54 +01:00
}
2022-08-12 17:23:51 +02:00
public static boolean addToClipboard ( CharSequence str ) {
2016-05-25 23:49:47 +02:00
try {
2016-06-24 12:27:15 +02:00
android . content . ClipboardManager clipboard = ( android . content . ClipboardManager ) ApplicationLoader . applicationContext . getSystemService ( Context . CLIPBOARD_SERVICE ) ;
2022-08-12 17:23:51 +02:00
if ( str instanceof Spanned ) {
android . content . ClipData clip = android . content . ClipData . newHtmlText ( " label " , str , CustomHtml . toHtml ( ( Spanned ) str ) ) ;
clipboard . setPrimaryClip ( clip ) ;
return true ;
} else {
android . content . ClipData clip = android . content . ClipData . newPlainText ( " label " , str ) ;
clipboard . setPrimaryClip ( clip ) ;
return true ;
}
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
}
2022-08-12 17:23:51 +02:00
return false ;
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 ) {
2022-09-16 20:48:21 +02:00
if ( secretChat | | ! BuildVars . NO_SCOPED_STORAGE | | ( Build . VERSION . SDK_INT > = 23 & & ApplicationLoader . applicationContext . checkSelfPermission ( android . Manifest . permission . READ_EXTERNAL_STORAGE ) ! = PackageManager . PERMISSION_GRANTED ) ) {
2021-11-09 02:49:31 +01:00
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 {
2022-09-16 20:48:21 +02:00
return " VID_ " + timeStamp + " .mp4 " ;
2021-11-09 02:49:31 +01:00
}
}
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 ;
2022-09-16 20:48:21 +02:00
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 ) ;
2022-09-16 20:48:21 +02:00
} else {
2019-12-31 14:08:08 +01:00
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 {
2022-09-16 20:48:21 +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 ) ;
2022-11-05 13:34:47 +01:00
Map < String , Integer > colorsReplacement = new HashMap < > ( ) ;
colorsReplacement . put ( " info1.** " , parentFragment . getThemedColor ( Theme . key_dialogTopBackground ) ) ;
colorsReplacement . put ( " info2.** " , parentFragment . getThemedColor ( Theme . key_dialogTopBackground ) ) ;
builder . setTopAnimation ( R . raw . not_available , AlertsCreator . NEW_DENY_DIALOG_TOP_ICON_SIZE , false , parentFragment . getThemedColor ( Theme . key_dialogTopBackground ) , colorsReplacement ) ;
builder . setTopAnimationIsNew ( true ) ;
2019-01-23 18:03:33 +01:00
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 ) {
2022-08-12 17:23:51 +02:00
intent . setDataAndType ( FileProvider . getUriForFile ( activity , ApplicationLoader . getApplicationId ( ) + " .provider " , f ) , realMimeType ! = null ? realMimeType : " text/plain " ) ;
2019-01-23 18:03:33 +01:00
} 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 ) {
2022-08-12 17:23:51 +02:00
intent . setDataAndType ( FileProvider . getUriForFile ( activity , ApplicationLoader . getApplicationId ( ) + " .provider " , f ) , " text/plain " ) ;
2019-01-23 18:03:33 +01:00
} 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 ) ;
2022-11-05 13:34:47 +01:00
Map < String , Integer > colorsReplacement = new HashMap < > ( ) ;
colorsReplacement . put ( " info1.** " , parentFragment . getThemedColor ( Theme . key_dialogTopBackground ) ) ;
colorsReplacement . put ( " info2.** " , parentFragment . getThemedColor ( Theme . key_dialogTopBackground ) ) ;
builder . setTopAnimation ( R . raw . not_available , AlertsCreator . NEW_DENY_DIALOG_TOP_ICON_SIZE , false , parentFragment . getThemedColor ( Theme . key_dialogTopBackground ) , colorsReplacement ) ;
builder . setTopAnimationIsNew ( true ) ;
2019-01-23 18:03:33 +01:00
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 ) {
2022-08-12 17:23:51 +02:00
intent . setDataAndType ( FileProvider . getUriForFile ( activity , ApplicationLoader . getApplicationId ( ) + " .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 ) {
2022-08-12 17:23:51 +02:00
intent . setDataAndType ( FileProvider . getUriForFile ( activity , ApplicationLoader . getApplicationId ( ) + " .provider " , f ) , " text/plain " ) ;
2017-03-31 01:58:05 +02:00
} 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
}
2022-11-05 13:34:47 +01:00
String mimeType = message . type = = MessageObject . TYPE_FILE | | message . type = = MessageObject . TYPE_TEXT ? 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 ) {
2022-08-12 17:23:51 +02:00
intent . setDataAndType ( FileProvider . getUriForFile ( activity , ApplicationLoader . getApplicationId ( ) + " .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 ) {
2022-08-12 17:23:51 +02:00
intent . setDataAndType ( FileProvider . getUriForFile ( activity , ApplicationLoader . getApplicationId ( ) + " .provider " , f ) , " text/plain " ) ;
2016-10-11 13:57:01 +02:00
} 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 ) ;
2022-12-30 13:32:20 +01:00
if ( activity instanceof LaunchActivity ) {
INavigationLayout layout = ( ( LaunchActivity ) activity ) . getActionBarLayout ( ) ;
BaseFragment fragment = layout . getLastFragment ( ) ;
if ( fragment instanceof ChatActivity ) {
( ( ChatActivity ) fragment ) . getUndoView ( ) . showWithAction ( 0 , UndoView . ACTION_PROXY_ADDED , null ) ;
} else {
NotificationCenter . getGlobalInstance ( ) . postNotificationName ( NotificationCenter . showBulletin , Bulletin . TYPE_SUCCESS , LocaleController . getString ( R . string . ProxyAddedSuccess ) ) ;
}
} else {
NotificationCenter . getGlobalInstance ( ) . postNotificationName ( NotificationCenter . showBulletin , Bulletin . TYPE_SUCCESS , LocaleController . getString ( R . string . ProxyAddedSuccess ) ) ;
}
2019-01-23 18:03:33 +01:00
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 ) ;
2022-09-16 20:48:21 +02:00
} else {
2019-02-08 03:30:32 +01:00
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 ) ) ;
}
2022-12-30 13:32:20 +01:00
public static float lerpAngle ( float a , float b , float f ) {
float delta = ( ( b - a + 360 + 180 ) % 360 ) - 180 ;
return ( a + delta * f + 360 ) % 360 ;
}
2019-12-31 14:08:08 +01:00
public static float lerp ( float a , float b , float f ) {
return a + f * ( b - a ) ;
}
2022-12-30 13:32:20 +01:00
public static double lerp ( double a , double b , float f ) {
return a + f * ( b - a ) ;
}
2019-12-31 14:08:08 +01:00
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 void lerp ( RectF a , RectF b , float f , RectF to ) {
if ( to ! = null ) {
to . set (
2022-09-16 20:48:21 +02:00
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-03-11 17:49:54 +01:00
) ;
}
}
public static void lerp ( Rect a , Rect b , float f , Rect to ) {
if ( to ! = null ) {
to . set (
2022-09-16 20:48:21 +02:00
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-03-11 17:49:54 +01:00
) ;
}
}
2022-09-16 20:48:21 +02:00
public static float cascade ( float fullAnimationT , float position , float count , float waveLength ) {
2022-08-12 17:23:51 +02:00
final float waveDuration = 1f / count * waveLength ;
2022-09-16 20:48:21 +02:00
final float waveOffset = position / count * ( 1f - waveDuration ) ;
2022-08-12 17:23:51 +02:00
return MathUtils . clamp ( ( fullAnimationT - waveOffset ) / waveDuration , 0 , 1 ) ;
}
2022-09-16 20:48:21 +02:00
public static int multiplyAlphaComponent ( int color , float k ) {
return ColorUtils . setAlphaComponent ( color , ( int ) ( Color . alpha ( color ) * k ) ) ;
}
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 < > ( ) ;
2022-09-16 20:48:21 +02:00
2022-02-01 14:00:45 +01:00
// 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 ) ;
} ;
}
2022-09-16 20:48:21 +02:00
2022-02-01 14:00:45 +01:00
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 ) ;
}
2022-09-16 20:48:21 +02:00
} catch ( Exception ignore ) {
}
2022-02-01 14:00:45 +01:00
}
}
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 " " ;
}
2022-09-16 20:48:21 +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-09-16 20:48:21 +02:00
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 ) ;
2022-09-16 20:48:21 +02:00
} 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 ) ;
2022-09-16 20:48:21 +02:00
} catch ( Exception ignore ) {
}
2022-04-16 16:43:17 +02:00
} ) ;
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 ;
}
2022-11-05 13:34:47 +01:00
public static void scrollToFragmentRow ( INavigationLayout parentLayout , String rowName ) {
2020-07-26 10:03:38 +02:00
if ( parentLayout = = null | | rowName = = null ) {
return ;
}
2022-11-05 13:34:47 +01:00
BaseFragment openingFragment = parentLayout . getFragmentStack ( ) . get ( parentLayout . getFragmentStack ( ) . size ( ) - 1 ) ;
2020-07-26 10:03:38 +02:00
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 ) {
2022-11-05 13:34:47 +01:00
if ( imageView . getDrawable ( ) = = newIcon ) {
return ;
}
2022-06-21 04:51:00 +02:00
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
2022-11-05 13:34:47 +01:00
public static void updateViewShow ( View view , boolean show ) {
updateViewShow ( view , show , true , true ) ;
}
public static void updateViewShow ( View view , boolean show , boolean scale , boolean animated ) {
2022-12-30 13:32:20 +01:00
updateViewShow ( view , show , scale , 0 , animated , null ) ;
2022-11-05 13:34:47 +01:00
}
public static void updateViewShow ( View view , boolean show , boolean scale , boolean animated , Runnable onDone ) {
2022-12-30 13:32:20 +01:00
updateViewShow ( view , show , scale , 0 , animated , onDone ) ;
}
public static void updateViewShow ( View view , boolean show , boolean scale , float translate , boolean animated , Runnable onDone ) {
2022-11-05 13:34:47 +01:00
if ( view = = null ) {
return ;
}
if ( view . getParent ( ) = = null ) {
animated = false ;
}
view . animate ( ) . setListener ( null ) . cancel ( ) ;
if ( ! animated ) {
view . setVisibility ( show ? View . VISIBLE : View . GONE ) ;
view . setTag ( show ? 1 : null ) ;
view . setAlpha ( 1f ) ;
view . setScaleX ( scale & & ! show ? 0f : 1f ) ;
view . setScaleY ( scale & & ! show ? 0f : 1f ) ;
2022-12-30 13:32:20 +01:00
if ( translate ! = 0 ) {
view . setTranslationY ( show ? 0 : AndroidUtilities . dp ( - 16 ) * translate ) ;
}
2022-11-05 13:34:47 +01:00
if ( onDone ! = null ) {
onDone . run ( ) ;
}
} else if ( show ) {
if ( view . getVisibility ( ) ! = View . VISIBLE ) {
view . setVisibility ( View . VISIBLE ) ;
view . setAlpha ( 0f ) ;
view . setScaleX ( scale ? 0 : 1 ) ;
view . setScaleY ( scale ? 0 : 1 ) ;
2022-12-30 13:32:20 +01:00
if ( translate ! = 0 ) {
view . setTranslationY ( AndroidUtilities . dp ( - 16 ) * translate ) ;
}
}
ViewPropertyAnimator animate = view . animate ( ) ;
animate = animate . alpha ( 1f ) . scaleY ( 1f ) . scaleX ( 1f ) . setInterpolator ( CubicBezierInterpolator . EASE_OUT_QUINT ) . setDuration ( 340 ) . withEndAction ( onDone ) ;
if ( translate ! = 0 ) {
animate . translationY ( 0 ) ;
2022-11-05 13:34:47 +01:00
}
2022-12-30 13:32:20 +01:00
animate . start ( ) ;
2022-11-05 13:34:47 +01:00
} else {
2022-12-30 13:32:20 +01:00
ViewPropertyAnimator animate = view . animate ( ) ;
animate = animate . alpha ( 0 ) . scaleY ( scale ? 0 : 1 ) . scaleX ( scale ? 0 : 1 ) . setListener ( new HideViewAfterAnimation ( view ) ) . setInterpolator ( CubicBezierInterpolator . EASE_OUT_QUINT ) . setDuration ( 340 ) . withEndAction ( onDone ) ;
if ( translate ! = 0 ) {
animate . translationY ( AndroidUtilities . dp ( - 16 ) * translate ) ;
}
animate . start ( ) ;
2022-11-05 13:34:47 +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 ( ) ;
2022-08-12 17:23:51 +02:00
return FileProvider . getUriForFile ( ApplicationLoader . applicationContext , ApplicationLoader . getApplicationId ( ) + " .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 ( ) {
2022-12-31 11:47:53 +01:00
return isAccessibilityTouchExplorationEnabled ( ) ;
2022-06-21 04:51:00 +02:00
}
2022-08-12 17:23:51 +02:00
public static CharSequence trim ( CharSequence text , int [ ] newStart ) {
if ( text = = null ) {
return null ;
}
int len = text . length ( ) ;
int st = 0 ;
while ( st < len & & text . charAt ( st ) < = ' ' ) {
st + + ;
}
while ( st < len & & text . charAt ( len - 1 ) < = ' ' ) {
len - - ;
}
if ( newStart ! = null ) {
newStart [ 0 ] = st ;
}
return ( st > 0 | | len < text . length ( ) ) ? text . subSequence ( st , len ) : text ;
}
2022-11-05 13:34:47 +01:00
// detect Error NO SPaCe left on device :(
public static boolean isENOSPC ( Exception e ) {
return (
Build . VERSION . SDK_INT > = Build . VERSION_CODES . LOLLIPOP & &
e instanceof IOException & &
( e . getCause ( ) instanceof ErrnoException & &
( ( ErrnoException ) e . getCause ( ) ) . errno = = OsConstants . ENOSPC ) | |
( e . getMessage ( ) ! = null & & e . getMessage ( ) . equalsIgnoreCase ( " no space left on device " ) )
) ;
}
public static CharSequence replaceCharSequence ( String what , CharSequence from , CharSequence obj ) {
SpannableStringBuilder spannableStringBuilder ;
if ( from instanceof SpannableStringBuilder ) {
spannableStringBuilder = ( SpannableStringBuilder ) from ;
} else {
spannableStringBuilder = new SpannableStringBuilder ( from ) ;
}
int index = TextUtils . indexOf ( from , what ) ;
if ( index > = 0 ) {
spannableStringBuilder . replace ( index , index + what . length ( ) , obj ) ;
}
return spannableStringBuilder ;
}
2022-12-30 13:32:20 +01:00
public static Bitmap makeBlurBitmap ( View view ) {
if ( view = = null ) {
return null ;
}
int w = ( int ) ( view . getWidth ( ) / 6 . 0f ) ;
int h = ( int ) ( view . getHeight ( ) / 6 . 0f ) ;
Bitmap bitmap = Bitmap . createBitmap ( w , h , Bitmap . Config . ARGB_8888 ) ;
Canvas canvas = new Canvas ( bitmap ) ;
canvas . scale ( 1 . 0f / 6 . 0f , 1 . 0f / 6 . 0f ) ;
canvas . drawColor ( Theme . getColor ( Theme . key_windowBackgroundWhite ) ) ;
view . draw ( canvas ) ;
Utilities . stackBlurBitmap ( bitmap , Math . max ( 7 , Math . max ( w , h ) / 180 ) ) ;
return bitmap ;
}
public static void makeGlobalBlurBitmap ( Utilities . Callback < Bitmap > onBitmapDone , float amount ) {
if ( onBitmapDone = = null ) {
return ;
}
List < View > views = null ;
try {
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . Q ) {
views = WindowInspector . getGlobalWindowViews ( ) ;
} else if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . JELLY_BEAN_MR1 ) {
Class wmgClass = Class . forName ( " android.view.WindowManagerGlobal " ) ;
Object wmgInstance = wmgClass . getMethod ( " getInstance " ) . invoke ( null , ( Object [ ] ) null ) ;
Method getViewRootNames = wmgClass . getMethod ( " getViewRootNames " ) ;
Method getRootView = wmgClass . getMethod ( " getRootView " , String . class ) ;
String [ ] rootViewNames = ( String [ ] ) getViewRootNames . invoke ( wmgInstance , ( Object [ ] ) null ) ;
views = new ArrayList < > ( ) ;
for ( String viewName : rootViewNames ) {
views . add ( ( View ) getRootView . invoke ( wmgInstance , viewName ) ) ;
}
} else if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . ICE_CREAM_SANDWICH & & Build . VERSION . SDK_INT < Build . VERSION_CODES . JELLY_BEAN_MR1 ) {
Class wmiClass = Class . forName ( " android.view.WindowManagerImpl " ) ;
Object wmiInstance = wmiClass . getMethod ( " getDefault " ) . invoke ( null ) ;
Field viewsField = wmiClass . getDeclaredField ( " mViews " ) ;
viewsField . setAccessible ( true ) ;
Object viewsObject = viewsField . get ( wmiInstance ) ;
if ( viewsObject instanceof List ) {
views = ( List < View > ) viewsField . get ( wmiInstance ) ;
} else if ( viewsObject instanceof View [ ] ) {
views = Arrays . asList ( ( View [ ] ) viewsField . get ( wmiInstance ) ) ;
}
}
} catch ( Exception e ) {
FileLog . e ( " makeGlobalBlurBitmap() " , e ) ;
}
if ( views = = null ) {
onBitmapDone . run ( null ) ;
return ;
}
final List < View > finalViews = views ;
//Utilities.themeQueue.postRunnable(() -> {
try {
int w = ( int ) ( AndroidUtilities . displaySize . x / amount ) ;
int h = ( int ) ( ( AndroidUtilities . displaySize . y + AndroidUtilities . statusBarHeight ) / amount ) ;
Bitmap bitmap = Bitmap . createBitmap ( w , h , Bitmap . Config . ARGB_8888 ) ;
Canvas canvas = new Canvas ( bitmap ) ;
canvas . scale ( 1 . 0f / amount , 1 . 0f / amount ) ;
canvas . drawColor ( Theme . getColor ( Theme . key_windowBackgroundWhite ) ) ;
int [ ] location = new int [ 2 ] ;
for ( int i = 0 ; i < finalViews . size ( ) ; + + i ) {
View view = finalViews . get ( i ) ;
ViewGroup . LayoutParams layoutParams = view . getLayoutParams ( ) ;
if ( layoutParams instanceof WindowManager . LayoutParams ) {
WindowManager . LayoutParams params = ( WindowManager . LayoutParams ) layoutParams ;
if ( ( params . flags & WindowManager . LayoutParams . FLAG_DIM_BEHIND ) ! = 0 ) {
canvas . drawColor ( ColorUtils . setAlphaComponent ( 0xFF000000 , ( int ) ( 0xFF * params . dimAmount ) ) ) ;
}
}
canvas . save ( ) ;
view . getLocationOnScreen ( location ) ;
canvas . translate ( location [ 0 ] / amount , location [ 1 ] / amount ) ;
try {
view . draw ( canvas ) ;
} catch ( Exception e ) {
}
canvas . restore ( ) ;
}
Utilities . stackBlurBitmap ( bitmap , Math . max ( ( int ) amount , Math . max ( w , h ) / 180 ) ) ;
AndroidUtilities . runOnUIThread ( ( ) - > {
onBitmapDone . run ( bitmap ) ;
} ) ;
} catch ( Exception e ) {
FileLog . e ( e ) ;
AndroidUtilities . runOnUIThread ( ( ) - > {
onBitmapDone . run ( null ) ;
} ) ;
}
// });
}
// rounds percents to be exact 100% in sum
public static int [ ] roundPercents ( float [ ] percents , int [ ] output ) {
if ( percents = = null ) {
throw new NullPointerException ( " percents or output is null " ) ;
}
if ( output = = null ) {
output = new int [ percents . length ] ;
}
if ( percents . length ! = output . length ) {
throw new IndexOutOfBoundsException ( " percents.length != output.length " ) ;
}
float sum = 0 ;
for ( int i = 0 ; i < percents . length ; + + i ) {
sum + = percents [ i ] ;
}
int roundedSum = 0 ;
for ( int i = 0 ; i < percents . length ; + + i ) {
roundedSum + = ( output [ i ] = ( int ) Math . floor ( percents [ i ] / sum * 100 ) ) ;
}
while ( roundedSum < 100 ) {
float maxError = 0 ;
int maxErrorIndex = - 1 ;
for ( int i = 0 ; i < percents . length ; + + i ) {
float error = ( percents [ i ] / sum ) - ( output [ i ] / 100f ) ;
if ( percents [ i ] > 0 & & error > = maxError ) {
maxErrorIndex = i ;
maxError = error ;
}
}
if ( maxErrorIndex < 0 ) {
break ;
}
output [ maxErrorIndex ] + + ;
roundedSum + + ;
}
return output ;
}
2014-07-03 00:39:05 +02:00
}