private static void appendSimpleName(StringBuilder sb, CharSequence fullName) {
    int dotIndex = TextUtils.lastIndexOf(fullName, '.');
    if (dotIndex < 0) {
      dotIndex = 0;
    }

    sb.append(fullName, dotIndex, fullName.length());
  }
  private void reflow(CharSequence s, int where, int before, int after) {
    if (s != mBase) return;

    CharSequence text = mDisplay;
    int len = text.length();

    // seek back to the start of the paragraph

    int find = TextUtils.lastIndexOf(text, '\n', where - 1);
    if (find < 0) find = 0;
    else find = find + 1;

    {
      int diff = where - find;
      before += diff;
      after += diff;
      where -= diff;
    }

    // seek forward to the end of the paragraph

    int look = TextUtils.indexOf(text, '\n', where + after);
    if (look < 0) look = len;
    else look++; // we want the index after the \n

    int change = look - (where + after);
    before += change;
    after += change;

    // seek further out to cover anything that is forced to wrap together

    if (text instanceof Spanned) {
      Spanned sp = (Spanned) text;
      boolean again;

      do {
        again = false;

        Object[] force = sp.getSpans(where, where + after, WrapTogetherSpan.class);

        for (int i = 0; i < force.length; i++) {
          int st = sp.getSpanStart(force[i]);
          int en = sp.getSpanEnd(force[i]);

          if (st < where) {
            again = true;

            int diff = where - st;
            before += diff;
            after += diff;
            where -= diff;
          }

          if (en > where + after) {
            again = true;

            int diff = en - (where + after);
            before += diff;
            after += diff;
          }
        }
      } while (again);
    }

    // find affected region of old layout

    int startline = getLineForOffset(where);
    int startv = getLineTop(startline);

    int endline = getLineForOffset(where + before);
    if (where + after == len) endline = getLineCount();
    int endv = getLineTop(endline);
    boolean islast = (endline == getLineCount());

    // generate new layout for affected text

    StaticLayout reflowed;

    synchronized (sLock) {
      reflowed = sStaticLayout;
      sStaticLayout = null;
    }

    if (reflowed == null) {
      reflowed = new StaticLayout(null);
    } else {
      reflowed.prepare();
    }

    reflowed.generate(
        text,
        where,
        where + after,
        getPaint(),
        getWidth(),
        getTextDirectionHeuristic(),
        getSpacingMultiplier(),
        getSpacingAdd(),
        false,
        true,
        mEllipsizedWidth,
        mEllipsizeAt);
    int n = reflowed.getLineCount();

    // If the new layout has a blank line at the end, but it is not
    // the very end of the buffer, then we already have a line that
    // starts there, so disregard the blank line.

    if (where + after != len && reflowed.getLineStart(n - 1) == where + after) n--;

    // remove affected lines from old layout

    mInts.deleteAt(startline, endline - startline);
    mObjects.deleteAt(startline, endline - startline);

    // adjust offsets in layout for new height and offsets

    int ht = reflowed.getLineTop(n);
    int toppad = 0, botpad = 0;

    if (mIncludePad && startline == 0) {
      toppad = reflowed.getTopPadding();
      mTopPadding = toppad;
      ht -= toppad;
    }
    if (mIncludePad && islast) {
      botpad = reflowed.getBottomPadding();
      mBottomPadding = botpad;
      ht += botpad;
    }

    mInts.adjustValuesBelow(startline, START, after - before);
    mInts.adjustValuesBelow(startline, TOP, startv - endv + ht);

    // insert new layout

    int[] ints;

    if (mEllipsize) {
      ints = new int[COLUMNS_ELLIPSIZE];
      ints[ELLIPSIS_START] = ELLIPSIS_UNDEFINED;
    } else {
      ints = new int[COLUMNS_NORMAL];
    }

    Directions[] objects = new Directions[1];

    for (int i = 0; i < n; i++) {
      ints[START] =
          reflowed.getLineStart(i)
              | (reflowed.getParagraphDirection(i) << DIR_SHIFT)
              | (reflowed.getLineContainsTab(i) ? TAB_MASK : 0);

      int top = reflowed.getLineTop(i) + startv;
      if (i > 0) top -= toppad;
      ints[TOP] = top;

      int desc = reflowed.getLineDescent(i);
      if (i == n - 1) desc += botpad;

      ints[DESCENT] = desc;
      objects[0] = reflowed.getLineDirections(i);

      if (mEllipsize) {
        ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i);
        ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i);
      }

      mInts.insertAt(startline + i, ints);
      mObjects.insertAt(startline + i, objects);
    }

    synchronized (sLock) {
      sStaticLayout = reflowed;
      reflowed.finish();
    }
  }