gt:         int startIndex = -1;
context: /*
   * This is the source code of Telegram for Android v. 5.x.x.
   * It is licensed under GNU GPL v. 2 or later.
   * You should have received a copy of the license in this archive (see LICENSE).
   *
   * Copyright Nikolai Kudashov, 2013-2018.
   */
  
  package org.telegram.messenger;
  
  import java.io.File;
  import java.io.InputStream;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Locale;
  
  import android.content.SharedPreferences;
  import android.graphics.Bitmap;
  import android.graphics.BitmapFactory;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.ColorFilter;
  import android.graphics.Paint;
  import android.graphics.PixelFormat;
  import android.graphics.Rect;
  import android.graphics.drawable.Drawable;
  import android.os.Build;
  import android.text.Spannable;
  import android.text.Spanned;
  import android.text.style.AbsoluteSizeSpan;
  import android.text.style.DynamicDrawableSpan;
  import android.text.style.ImageSpan;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.TextView;
  
  public class Emoji {
  
      private static HashMap<CharSequence, DrawableInfo> rects = new HashMap<>();
      private static int drawImgSize;
      private static int bigImgSize;
      private static boolean inited = false;
      private static Paint placeholderPaint;
      private static int[] emojiCounts = new int[]{1620, 184, 115, 328, 125, 206, 288, 258};
      private static Bitmap[][] emojiBmp = new Bitmap[8][];
      private static boolean[][] loadingEmoji = new boolean[8][];
  
      public static HashMap<String, Integer> emojiUseHistory = new HashMap<>();
      public static ArrayList<String> recentEmoji = new ArrayList<>();
      public static HashMap<String, String> emojiColor = new HashMap<>();
      private static boolean recentEmojiLoaded;
      private static Runnable invalidateUiRunnable = () -> NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.emojiDidLoad);
  
      private final static int MAX_RECENT_EMOJI_COUNT = 48;
  
      static {
          drawImgSize = AndroidUtilities.dp(20);
          bigImgSize = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 40 : 34);
          for (int a = 0; a < emojiBmp.length; a++) {
              emojiBmp[a] = new Bitmap[emojiCounts[a]];
              loadingEmoji[a] = new boolean[emojiCounts[a]];
          }
  
          for (int j = 0; j < EmojiData.data.length; j++) {
              int position;
              for (int i = 0; i < EmojiData.data[j].length; i++) {
                  rects.put(EmojiData.data[j][i], new DrawableInfo((byte) j, (short) i, i));
              }
          }
          placeholderPaint = new Paint();
          placeholderPaint.setColor(0x00000000);
      }
  
      private static void loadEmoji(final byte page, final short page2) {
          try {
              float scale;
              int imageResize = 1;
              if (AndroidUtilities.density <= 1.0f) {
                  scale = 2.0f;
                  imageResize = 2;
              } else if (AndroidUtilities.density <= 1.5f) {
                  scale = 2.0f;
              } else if (AndroidUtilities.density <= 2.0f) {
                  scale = 2.0f;
              } else {
                  scale = 2.0f;
              }
  
              String imageName;
              File imageFile;
  
              try {
                  for (int a = 13; a < 16; a++) {
                      imageName = String.format(Locale.US, "v%d_emoji%.01fx_%d.png", a, scale, page);
                      imageFile = ApplicationLoader.applicationContext.getFileStreamPath(imageName);
                      if (imageFile.exists()) {
                          imageFile.delete();
                      }
                  }
              } catch (Exception e) {
                  FileLog.e(e);
              }
              Bitmap bitmap = null;
              try {
                  InputStream is = ApplicationLoader.applicationContext.getAssets().open("emoji/" + String.format(Locale.US, "%d_%d.png", page, page2));
                  BitmapFactory.Options opts = new BitmapFactory.Options();
                  opts.inJustDecodeBounds = false;
                  opts.inSampleSize = imageResize;
                  bitmap = BitmapFactory.decodeStream(is, null, opts);
                  is.close();
              } catch (Throwable e) {
                  FileLog.e(e);
              }
  
              final Bitmap finalBitmap = bitmap;
              emojiBmp[page][page2] = finalBitmap;
              AndroidUtilities.cancelRunOnUIThread(invalidateUiRunnable);
              AndroidUtilities.runOnUIThread(invalidateUiRunnable);
          } catch (Throwable x) {
              if (BuildVars.LOGS_ENABLED) {
                  FileLog.e("Error loading emoji", x);
              }
          }
      }
  
      public static void invalidateAll(View view) {
          if (view instanceof ViewGroup) {
              ViewGroup g = (ViewGroup) view;
              for (int i = 0; i < g.getChildCount(); i++) {
                  invalidateAll(g.getChildAt(i));
              }
          } else if (view instanceof TextView) {
              view.invalidate();
          }
      }
  
      public static String fixEmoji(String emoji) {
          char ch;
          int length = emoji.length();
          for (int a = 0; a < length; a++) {
              ch = emoji.charAt(a);
              if (ch >= 0xD83C && ch <= 0xD83E) {
                  if (ch == 0xD83C && a < length - 1) {
                      ch = emoji.charAt(a + 1);
                      if (ch == 0xDE2F || ch == 0xDC04 || ch == 0xDE1A || ch == 0xDD7F) {
                          emoji = emoji.substring(0, a + 2) + "\uFE0F" + emoji.substring(a + 2);
                          length++;
                          a += 2;
                      } else {
                          a++;
                      }
                  } else {
                      a++;
                  }
              } else if (ch == 0x20E3) {
                  return emoji;
              } else if (ch >= 0x203C && ch <= 0x3299) {
                  if (EmojiData.emojiToFE0FMap.containsKey(ch)) {
                      emoji = emoji.substring(0, a + 1) + "\uFE0F" + emoji.substring(a + 1);
                      length++;
                      a++;
                  }
              }
          }
          return emoji;
      }
  
      public static EmojiDrawable getEmojiDrawable(CharSequence code) {
          DrawableInfo info = rects.get(code);
          if (info == null) {
              CharSequence newCode = EmojiData.emojiAliasMap.get(code);
              if (newCode != null) {
                  info = Emoji.rects.get(newCode);
              }
          }
          if (info == null) {
              if (BuildVars.LOGS_ENABLED) {
                  FileLog.d("No drawable for emoji " + code);
              }
              return null;
          }
          EmojiDrawable ed = new EmojiDrawable(info);
          ed.setBounds(0, 0, drawImgSize, drawImgSize);
          return ed;
      }
  
      public static boolean isValidEmoji(CharSequence code) {
          DrawableInfo info = rects.get(code);
          if (info == null) {
              CharSequence newCode = EmojiData.emojiAliasMap.get(code);
              if (newCode != null) {
                  info = Emoji.rects.get(newCode);
              }
          }
          return info != null;
      }
  
      public static Drawable getEmojiBigDrawable(String code) {
          EmojiDrawable ed = getEmojiDrawable(code);
          if (ed == null) {
              CharSequence newCode = EmojiData.emojiAliasMap.get(code);
              if (newCode != null) {
                  ed = Emoji.getEmojiDrawable(newCode);
              }
          }
          if (ed == null) {
              return null;
          }
          ed.setBounds(0, 0, bigImgSize, bigImgSize);
          ed.fullSize = true;
          return ed;
      }
  
      public static class EmojiDrawable extends Drawable {
          private DrawableInfo info;
          private boolean fullSize = false;
          private static Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
          private static Rect rect = new Rect();
  
          public EmojiDrawable(DrawableInfo i) {
              info = i;
          }
  
          public DrawableInfo getDrawableInfo() {
              return info;
          }
  
          public Rect getDrawRect() {
              Rect original = getBounds();
              int cX = original.centerX(), cY = original.centerY();
              rect.left = cX - (fullSize ? bigImgSize : drawImgSize) / 2;
              rect.right = cX + (fullSize ? bigImgSize : drawImgSize) / 2;
              rect.top = cY - (fullSize ? bigImgSize : drawImgSize) / 2;
              rect.bottom = cY + (fullSize ? bigImgSize : drawImgSize) / 2;
              return rect;
          }
  
          @Override
          public void draw(Canvas canvas) {
              Rect b;
              if (fullSize) {
                  b = getDrawRect();
              } else {
                  b = getBounds();
              }
  
              if (SharedConfig.useSystemEmoji) {
                  final float offset = (fullSize ? bigImgSize : drawImgSize) * -0.2f;
                  paint.setTextSize(b.width() * 0.8f);
                  canvas.drawText(EmojiData.data[info.page][info.emojiIndex], b.left, b.bottom + offset, paint);
                  return;
              }
  
              if (emojiBmp[info.page][info.page2] == null) {
                  if (loadingEmoji[info.page][info.page2]) {
                      return;
                  }
                  loadingEmoji[info.page][info.page2] = true;
                  Utilities.globalQueue.postRunnable(() -> {
                      loadEmoji(info.page, info.page2);
                      loadingEmoji[info.page][info.page2] = false;
                  });
                  canvas.drawRect(getBounds(), placeholderPaint);
                  return;
              }
  
              /*
              Rect b;
              if (fullSize) {
                  b = getDrawRect();
              } else {
                  b = getBounds();
              }
              */
  
              //if (!canvas.quickReject(b.left, b.top, b.right, b.bottom, Canvas.EdgeType.AA)) {
              canvas.drawBitmap(emojiBmp[info.page][info.page2], null, b, paint);
              //}
          }
  
          @Override
          public int getOpacity() {
              return PixelFormat.TRANSPARENT;
          }
  
          @Override
          public void setAlpha(int alpha) {
  
          }
  
          @Override
          public void setColorFilter(ColorFilter cf) {
  
          }
      }
  
      private static class DrawableInfo {
          public byte page;
          public short page2;
          public int emojiIndex;
  
          public DrawableInfo(byte p, short p2, int index) {
              page = p;
              page2 = p2;
              emojiIndex = index;
          }
      }
  
      private static boolean inArray(char c, char[] a) {
          for (char cc : a) {
              if (cc == c) {
                  return true;
              }
          }
          return false;
      }
  
      public static CharSequence replaceEmoji(CharSequence cs, Paint.FontMetricsInt fontMetrics, int size, boolean createNew) {
          return replaceEmoji(cs, fontMetrics, size, createNew, null);
      }
  
      public static CharSequence replaceEmoji(CharSequence cs, Paint.FontMetricsInt fontMetrics, int size, boolean createNew, int[] emojiOnly) {
          if (cs == null || cs.length() == 0) {
              return cs;
          }
          Spannable s;
          if (!createNew && cs instanceof Spannable) {
              s = (Spannable) cs;
          } else {
              s = Spannable.Factory.getInstance().newSpannable(cs.toString());
          }
  
          if (SharedConfig.useSystemEmoji && !SharedConfig.allowBigEmoji) {
              return s;
          }
  
          long buf = 0;
          int emojiCount = 0;
          char c;
  