public void expand(boolean animate) {

    if (!truncated) {
      return;
    }

    truncated = false;
    if (!animate) {
      requestLayout();
      return;
    }

    ResizeAnimation expandAnimation =
        new ResizeAnimation(getHeight() + expandedLayout.getHeight() - truncatedLayout.getHeight());

    expandAnimation.setDuration(400);
    expandAnimation.setAnimationListener(
        new Animation.AnimationListener() {
          @Override
          public void onAnimationStart(Animation animation) {
            animating = true;
          }

          @Override
          public void onAnimationEnd(Animation animation) {
            animating = false;
          }

          @Override
          public void onAnimationRepeat(Animation animation) {}
        });

    startAnimation(expandAnimation);
  }
Example #2
0
  @Override
  public void onDraw(Canvas canvas) {
    // Log.d("TFV", "Font metrics float: "+paint.getFontMetrics(null) * textLines.length +" font
    // metrics int: "+paint.getFontMetricsInt(null)*textLines.length+" layout height:
    // "+layout.getHeight()+" layout line bottom: "+layout.getLineBottom(layout.getLineCount() -
    // 1)+" pad top: "+layout.getTopPadding()+" pad bottom: "+layout.getBottomPadding()+" attempt:
    // "+(paint.getFontMetricsInt(null)*textLines.length - layout.getTopPadding() +
    // layout.getBottomPadding()));

    // canvas.drawColor(backgroundColor); // wipe canvas (just in case)-- doesn't seem necessary but
    // try this in case of bugs!

    // Just in case (do not remove!):
    if (layout == null) updateLayout();

    // Calculate new height offset for vertical text centering -- want to start drawing text at
    // (container height - text height) /2 = (container height - (text box height - (negative
    // padding)) / 2 = (container height - text box height + negative padding) / 2
    float heightOffset =
        0.5f
            * (this.getHeight()
                - layout.getHeight()
                + layout.getTopPadding() /* this is negative! */);

    // Shift canvas downwards and rightwards so that the text will be vertically and horizontally
    // centred:
    canvas.translate(this.getPaddingLeft(), heightOffset);

    // Draw text on shifted canvas:
    layout.draw(canvas);

    // Undo translate:
    canvas.restore();
  }
  protected void drawCenterText(Canvas c) {

    SpannableString centerText = mChart.getCenterText();

    if (mChart.isDrawCenterTextEnabled() && centerText != null) {

      PointF center = mChart.getCenterCircleBox();

      float innerRadius =
          mChart.isDrawHoleEnabled() && mChart.isHoleTransparent()
              ? mChart.getRadius() * (mChart.getHoleRadius() / 100f)
              : mChart.getRadius();

      RectF holeRect = mRectBuffer[0];
      holeRect.left = center.x - innerRadius;
      holeRect.top = center.y - innerRadius;
      holeRect.right = center.x + innerRadius;
      holeRect.bottom = center.y + innerRadius;
      RectF boundingRect = mRectBuffer[1];
      boundingRect.set(holeRect);

      float radiusPercent = mChart.getCenterTextRadiusPercent();
      if (radiusPercent > 0.0) {
        boundingRect.inset(
            (boundingRect.width() - boundingRect.width() * radiusPercent) / 2.f,
            (boundingRect.height() - boundingRect.height() * radiusPercent) / 2.f);
      }

      if (!centerText.equals(mCenterTextLastValue) || !boundingRect.equals(mCenterTextLastBounds)) {

        // Next time we won't recalculate StaticLayout...
        mCenterTextLastBounds.set(boundingRect);
        mCenterTextLastValue = centerText;

        float width = mCenterTextLastBounds.width();

        // If width is 0, it will crash. Always have a minimum of 1
        mCenterTextLayout =
            new StaticLayout(
                centerText,
                0,
                centerText.length(),
                mCenterTextPaint,
                (int) Math.max(Math.ceil(width), 1.f),
                Layout.Alignment.ALIGN_CENTER,
                1.f,
                0.f,
                false);
      }

      float layoutHeight = mCenterTextLayout.getHeight();

      c.save();
      c.translate(
          boundingRect.left, boundingRect.top + (boundingRect.height() - layoutHeight) / 2.f);
      mCenterTextLayout.draw(c);
      c.restore();
    }
  }
Example #4
0
  /** @param popupText the popupText to set */
  public void setText(String text) {
    if (text == null) this.text = "";
    else this.text = text;

    layout = new StaticLayout(this.text, tp, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, true);
    this.width = layout.getWidth();
    this.height = layout.getHeight();
  }
 // Set the text size of the text paint object and use a static layout to render text off screen
 // before measuring
 private int getTextHeight(CharSequence source, TextPaint paint, int width, float textSize) {
   // Update the text paint object
   paint.setTextSize(textSize);
   // Measure using a static layout
   StaticLayout layout =
       new StaticLayout(
           source, paint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
   return layout.getHeight();
 }
 // Set the text size of the text paint object and use a static layout to render text off screen
 // before measuring
 private int getTextHeight(CharSequence source, TextPaint paint, int width, float textSize) {
   // modified: make a copy of the original TextPaint object for measuring
   // (apparently the object gets modified while measuring, see also the
   // docs for TextView.getPaint() (which states to access it read-only)
   TextPaint paintCopy = new TextPaint(paint);
   // Update the text paint object
   paintCopy.setTextSize(textSize);
   // Measure using a static layout
   StaticLayout layout =
       new StaticLayout(
           source, paintCopy, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
   return layout.getHeight();
 }
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public int onTestSize(int suggestedSize, RectF availableSPace) {
          mPaint.setTextSize(suggestedSize);
          String text = getText().toString();
          boolean singleline = getMaxLines() == 1;
          if (singleline) {
            mTextRect.bottom = mPaint.getFontSpacing();
            mTextRect.right = mPaint.measureText(text);
          } else {
            StaticLayout layout =
                new StaticLayout(
                    text,
                    mPaint,
                    mWidthLimit,
                    Alignment.ALIGN_NORMAL,
                    mSpacingMult,
                    mSpacingAdd,
                    true);
            // return early if we have more lines
            if (getMaxLines() != NO_LINE_LIMIT && layout.getLineCount() > getMaxLines()) {
              return 1;
            }
            mTextRect.bottom = layout.getHeight();
            int maxWidth = -1;
            for (int i = 0; i < layout.getLineCount(); i++) {
              if (maxWidth < layout.getLineWidth(i)) {
                maxWidth = (int) layout.getLineWidth(i);
              }
            }
            mTextRect.right = maxWidth;
          }

          mTextRect.offsetTo(0, 0);
          if (availableSPace.contains(mTextRect)) {
            // may be too small, don't worry we will find the best match
            return -1;
          } else {
            // too big
            return 1;
          }
        }
 public void setText(String text) {
   if (text == null || text.length() == 0) {
     setVisibility(GONE);
     return;
   }
   if (text != null && oldText != null && text.equals(oldText)) {
     return;
   }
   oldText = text;
   setVisibility(VISIBLE);
   if (AndroidUtilities.isTablet()) {
     width = (int) (AndroidUtilities.getMinTabletSide() * 0.7f);
   } else {
     width =
         (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f);
   }
   SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
   String help = LocaleController.getString("BotInfoTitle", R.string.BotInfoTitle);
   stringBuilder.append(help);
   stringBuilder.append("\n\n");
   stringBuilder.append(text);
   MessageObject.addLinks(stringBuilder);
   stringBuilder.setSpan(
       new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")),
       0,
       help.length(),
       Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
   textLayout =
       new StaticLayout(
           stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
   width = 0;
   height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18);
   int count = textLayout.getLineCount();
   for (int a = 0; a < count; a++) {
     width =
         (int) Math.ceil(Math.max(width, textLayout.getLineWidth(a) - textLayout.getLineLeft(a)));
   }
   width += AndroidUtilities.dp(4 + 18);
 }
Example #9
0
    private void renderBottomLabel(
        Canvas canvas, RadRect dataPointSlot, String labelText, StaticLayout textBounds) {
      RectF labelBounds = new RectF();
      double height = textBounds.getHeight() + this.labelPadding * 2;
      double top = dataPointSlot.getBottom() + this.labelMargin;
      labelBounds.set(
          (float) dataPointSlot.x,
          (float) top,
          (float) dataPointSlot.getRight(),
          (float) (top + height));

      canvas.drawRect(
          labelBounds.left, labelBounds.top, labelBounds.right, labelBounds.bottom, this.lowFill);
      canvas.drawRect(
          labelBounds.left, labelBounds.top, labelBounds.right, labelBounds.bottom, this.stroke);
      canvas.drawText(
          labelText,
          (float)
              (dataPointSlot.x + (dataPointSlot.width / 2.0) - textBounds.getLineWidth(0) / 2.0f),
          labelBounds.centerY() + textBounds.getLineBottom(0) - textBounds.getLineBaseline(0),
          paint);
    }
  static Bitmap smartLines(
      Context context, Bitmap icon, String header, String[] lines, FontCache.FontSize size) {

    Properties props = BitmapCache.getProperties(context, "notification.xml");

    final int textTop = Integer.parseInt(props.getProperty("textTop", "24"));
    final int textLeft = Integer.parseInt(props.getProperty("textLeft", "3"));
    final int textWidth = Integer.parseInt(props.getProperty("textWidth", "90"));
    final int textHeight = Integer.parseInt(props.getProperty("textHeight", "69"));

    final int iconTop = Integer.parseInt(props.getProperty("iconTop", "0"));
    final int iconLeft = Integer.parseInt(props.getProperty("iconLeft", "0"));

    final int headerLeft = Integer.parseInt(props.getProperty("headerLeft", "20"));
    final int headerBaseline = Integer.parseInt(props.getProperty("headerBaseline", "15"));

    final int headerColor =
        props.getProperty("headerColor", "white").equalsIgnoreCase("black")
            ? Color.BLACK
            : Color.WHITE;
    final int textColor =
        props.getProperty("textColor", "black").equalsIgnoreCase("black")
            ? Color.BLACK
            : Color.WHITE;

    FontInfo font = FontCache.instance(context).Get(size);

    Bitmap bitmap = Bitmap.createBitmap(96, 96, Bitmap.Config.RGB_565);
    Canvas canvas = new Canvas(bitmap);

    Paint paintHead = new Paint();
    paintHead.setColor(headerColor);
    paintHead.setTextSize(FontCache.instance(context).Large.size);
    paintHead.setTypeface(FontCache.instance(context).Large.face);

    Paint paint = new Paint();
    paint.setColor(textColor);
    paint.setTextSize(font.size);
    paint.setTypeface(font.face);

    canvas.drawColor(Color.WHITE);

    canvas.drawBitmap(Utils.getBitmap(context, "notify_background.png"), 0, 0, null);

    int iconHeight = 16;
    if (icon != null) {
      iconHeight = Math.max(16, icon.getHeight()); // make sure the text fits

      // align icon to bottom of text
      canvas.drawBitmap(icon, iconLeft, iconTop + iconHeight - icon.getHeight(), paint);
    }

    canvas.drawText(header, headerLeft, headerBaseline, paintHead);

    String body = "";
    for (String line : lines) {
      if (body.length() > 0) body += "\n\n";
      body += line;
    }

    TextPaint textPaint = new TextPaint(paint);
    StaticLayout staticLayout =
        new StaticLayout(
            body, textPaint, textWidth, android.text.Layout.Alignment.ALIGN_CENTER, 1.3f, 0, false);

    int layoutHeight = staticLayout.getHeight();
    int textY = textTop + (textHeight / 2) - (layoutHeight / 2);
    if (textY < textTop) textY = textTop;

    canvas.translate(textLeft, textY); // position the text
    staticLayout.draw(canvas);

    return bitmap;
  }
Example #11
0
  /**
   * draws the description text in the center of the pie chart makes most sense when center-hole is
   * enabled
   */
  protected void drawCenterText(Canvas c) {

    CharSequence centerText = mChart.getCenterText();

    if (mChart.isDrawCenterTextEnabled() && centerText != null) {

      PointF center = mChart.getCenterCircleBox();

      float innerRadius =
          mChart.isDrawHoleEnabled()
              ? mChart.getRadius() * (mChart.getHoleRadius() / 100f)
              : mChart.getRadius();

      RectF holeRect = mRectBuffer[0];
      holeRect.left = center.x - innerRadius;
      holeRect.top = center.y - innerRadius;
      holeRect.right = center.x + innerRadius;
      holeRect.bottom = center.y + innerRadius;
      RectF boundingRect = mRectBuffer[1];
      boundingRect.set(holeRect);

      float radiusPercent = mChart.getCenterTextRadiusPercent() / 100f;
      if (radiusPercent > 0.0) {
        boundingRect.inset(
            (boundingRect.width() - boundingRect.width() * radiusPercent) / 2.f,
            (boundingRect.height() - boundingRect.height() * radiusPercent) / 2.f);
      }

      if (!centerText.equals(mCenterTextLastValue) || !boundingRect.equals(mCenterTextLastBounds)) {

        // Next time we won't recalculate StaticLayout...
        mCenterTextLastBounds.set(boundingRect);
        mCenterTextLastValue = centerText;

        float width = mCenterTextLastBounds.width();

        // If width is 0, it will crash. Always have a minimum of 1
        mCenterTextLayout =
            new StaticLayout(
                centerText,
                0,
                centerText.length(),
                mCenterTextPaint,
                (int) Math.max(Math.ceil(width), 1.f),
                Layout.Alignment.ALIGN_CENTER,
                1.f,
                0.f,
                false);
      }

      // I wish we could make an ellipse clipping path on Android to clip to the hole...
      // If we ever find out how, this is the place to add it, based on holeRect

      // float layoutWidth = Utils.getStaticLayoutMaxWidth(mCenterTextLayout);
      float layoutHeight = mCenterTextLayout.getHeight();

      c.save();
      c.translate(
          boundingRect.left, boundingRect.top + (boundingRect.height() - layoutHeight) / 2.f);
      mCenterTextLayout.draw(c);
      c.restore();

      //            }
      //
      //        else {
      //
      //
      //                // get all lines from the text
      //                String[] lines = centerText.toString().split("\n");
      //
      //                float maxlineheight = 0f;
      //
      //                // calc the maximum line height
      //                for (String line : lines) {
      //                    float curHeight = Utils.calcTextHeight(mCenterTextPaint, line);
      //                    if (curHeight > maxlineheight)
      //                        maxlineheight = curHeight;
      //                }
      //
      //                float linespacing = maxlineheight * 0.25f;
      //
      //                float totalheight = maxlineheight * lines.length - linespacing *
      // (lines.length - 1);
      //
      //                int cnt = lines.length;
      //
      //                float y = center.y;
      //
      //                for (int i = 0; i < lines.length; i++) {
      //
      //                    String line = lines[lines.length - i - 1];
      //
      //
      //
      //                    c.drawText(line, center.x, y
      //                                    + maxlineheight * cnt - totalheight / 2f,
      //                            mCenterTextPaint);
      //                    cnt--;
      //                    y -= linespacing;
      //                }
      //            }
    }
  }
Example #12
0
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    measureWidth(widthMeasureSpec);
    this.imgSize = (int) ((JokerView.windowH / 5) * 0.6);
    this.rightBorder = (int) (JokerView.windowH / 5);
    int TextWidth = this.width - this.imgSize - this.rightBorder;

    Rect bounds = new Rect();
    LayoutTextPaint = new TextPaint();
    LayoutTextPaint.setTextSize((float) (UI_Size_Base.that.getScaledFontSize() * 1.3));
    LayoutTextPaint.getTextBounds("T", 0, 1, bounds);
    LineSep = bounds.height() / 3;

    LayoutTextPaint.setAntiAlias(true);
    LayoutTextPaint.setColor(Global.getColor(R.attr.TextColor));

    if (joker.Tage == -1) // this Joker is Owner
    {
      LayoutTage =
          new StaticLayout(
              "Owner von diesem Cache",
              LayoutTextPaint,
              TextWidth,
              Alignment.ALIGN_NORMAL,
              1.0f,
              0.0f,
              false);
    } else {
      LayoutTage =
          new StaticLayout(
              "gefunden vor " + String.valueOf(joker.Tage) + " Tagen",
              LayoutTextPaint,
              TextWidth,
              Alignment.ALIGN_NORMAL,
              1.0f,
              0.0f,
              false);
    }
    LayoutTelefon =
        new StaticLayout(
            "Tel: " + joker.Telefon,
            LayoutTextPaint,
            TextWidth,
            Alignment.ALIGN_NORMAL,
            1.0f,
            0.0f,
            false);
    LayoutBemerkung =
        new StaticLayout(
            "Bem.:" + joker.Bemerkung,
            LayoutTextPaint,
            TextWidth,
            Alignment.ALIGN_NORMAL,
            1.0f,
            0.0f,
            false);
    LayoutTextPaintBold = new TextPaint(LayoutTextPaint);
    LayoutTextPaintBold.setFakeBoldText(true);
    LayoutName =
        new StaticLayout(
            joker.GCLogin + " (" + joker.Vorname + ", " + joker.Name + ")",
            LayoutTextPaintBold,
            TextWidth,
            Alignment.ALIGN_NORMAL,
            1.0f,
            0.0f,
            false);
    this.height =
        (LineSep * 5)
            + LayoutTage.getHeight()
            + LayoutTelefon.getHeight()
            + LayoutBemerkung.getHeight()
            + LayoutName.getHeight();

    setMeasuredDimension(this.width, this.height);
  }
  public Bitmap update(Context context, boolean preview, int watchType) {

    TextPaint paintSmall = new TextPaint();
    paintSmall.setColor(Color.BLACK);
    paintSmall.setTextSize(FontCache.instance(context).Small.size);
    paintSmall.setTypeface(FontCache.instance(context).Small.face);

    TextPaint paintSmallOutline = new TextPaint();
    paintSmallOutline.setColor(Color.WHITE);
    paintSmallOutline.setTextSize(FontCache.instance(context).Small.size);
    paintSmallOutline.setTypeface(FontCache.instance(context).Small.face);

    TextPaint paintLarge = new TextPaint();
    paintLarge.setColor(Color.BLACK);
    paintLarge.setTextSize(FontCache.instance(context).Large.size);
    paintLarge.setTypeface(FontCache.instance(context).Large.face);

    TextPaint paintLargeOutline = new TextPaint();
    paintLargeOutline.setColor(Color.WHITE);
    paintLargeOutline.setTextSize(FontCache.instance(context).Large.size);
    paintLargeOutline.setTypeface(FontCache.instance(context).Large.face);

    MediaControl.TrackInfo lastTrack = MediaControl.getLastTrack();

    if (watchType == WatchType.DIGITAL) {

      Bitmap bitmap = Bitmap.createBitmap(96, 96, Bitmap.Config.RGB_565);
      Canvas canvas = new Canvas(bitmap);
      canvas.drawColor(Color.WHITE);

      if (lastTrack.isEmpty()) {
        canvas.drawBitmap(Utils.getBitmap(context, "media_player_idle.png"), 0, 0, null);
      } else {
        canvas.drawBitmap(Utils.getBitmap(context, "media_player.png"), 0, 0, null);

        StringBuilder lowerText = new StringBuilder();
        if (!lastTrack.artist.equals("")) {
          lowerText.append(lastTrack.artist);
        }
        if (!lastTrack.album.equals("")) {
          if (lowerText.length() > 0) lowerText.append("\n\n");
          lowerText.append(lastTrack.album);
        }

        Utils.autoText(
            context,
            canvas,
            lastTrack.track,
            0,
            8,
            96,
            35,
            Layout.Alignment.ALIGN_CENTER,
            Color.BLACK);
        Utils.autoText(
            context,
            canvas,
            lowerText.toString(),
            0,
            54,
            96,
            35,
            Layout.Alignment.ALIGN_CENTER,
            Color.BLACK);
      }
      drawDigitalAppSwitchIcon(context, canvas, preview);

      return bitmap;
    } else if (watchType == WatchType.ANALOG) {
      Bitmap bitmap = Bitmap.createBitmap(80, 32, Bitmap.Config.RGB_565);
      Canvas canvas = new Canvas(bitmap);
      canvas.drawColor(Color.WHITE);

      if (lastTrack.isEmpty()) {
        canvas.drawBitmap(Utils.getBitmap(context, "media_player_idle_oled.png"), 0, 0, null);
      } else {
        canvas.drawBitmap(Utils.getBitmap(context, "media_player_oled.png"), 0, 0, null);

        TextPaint tp = null;
        if (paintLarge.measureText(lastTrack.track) < 75) {
          tp = paintLarge;
        } else {
          tp = paintSmall;
        }

        canvas.save();
        StaticLayout layout =
            new StaticLayout(
                lastTrack.track, tp, 75, Layout.Alignment.ALIGN_CENTER, 1.2f, 0, false);
        int height = layout.getHeight();
        int textY = 8 - (height / 2);
        if (textY < 0) {
          textY = 0;
        }
        canvas.translate(0, textY); // position the text
        canvas.clipRect(0, 0, 75, 16);
        layout.draw(canvas);
        canvas.restore();

        canvas.save();
        StringBuilder lowerText = new StringBuilder();
        if (!lastTrack.artist.equals("")) {
          lowerText.append(lastTrack.artist);
        }
        if (!lastTrack.album.equals("")) {
          if (lowerText.length() > 0) lowerText.append("\n\n");
          lowerText.append(lastTrack.album);
        }

        if (paintLarge.measureText(lowerText.toString()) < 75) {
          tp = paintLarge;
        } else {
          tp = paintSmall;
        }

        layout =
            new StaticLayout(
                lowerText.toString(), tp, 75, Layout.Alignment.ALIGN_CENTER, 1.0f, 0, false);
        height = layout.getHeight();
        textY = 24 - (height / 2);
        if (textY < 16) {
          textY = 16;
        }
        canvas.translate(0, textY); // position the text
        canvas.clipRect(0, 0, 75, 16);
        layout.draw(canvas);
        canvas.restore();
      }

      return bitmap;
    }

    return null;
  }
Example #14
0
    public void build(MessageWireframe wireframe, int desiredWidth, StelsApplication application) {

      Logger.d(TAG, "Build layout start");

      checkResources(application);

      senderPaint = initTextPaint();
      senderPaint.setTypeface(FontController.loadTypeface(application, "regular"));
      senderPaint.setTextSize(bodyPaint.getTextSize());
      senderPaint.setColor(0xff000000);

      forwardingPaint = initTextPaint();
      forwardingPaint.setTypeface(FontController.loadTypeface(application, "light"));
      forwardingPaint.setTextSize(bodyPaint.getTextSize());
      forwardingPaint.setColor(0xff000000);

      this.layoutDesiredWidth = desiredWidth;
      this.isOut = wireframe.message.isOut();
      this.showState = isOut;
      this.isGroup = wireframe.message.getPeerType() == PeerType.PEER_CHAT && !isOut;
      if (isGroup) {
        User user = wireframe.senderUser;
        this.senderName = user.getDisplayName();
        if (!wireframe.message.isForwarded()) {
          senderPaint.setColor(
              Placeholders.USER_PLACEHOLDERS_COLOR[
                  wireframe.message.getSenderId() % Placeholders.USER_PLACEHOLDERS_COLOR.length]);
          forwardingPaint.setColor(
              Placeholders.USER_PLACEHOLDERS_COLOR[
                  wireframe.message.getSenderId() % Placeholders.USER_PLACEHOLDERS_COLOR.length]);
        }
      }

      if (wireframe.message.isForwarded()) {
        isForwarded = true;
        this.forwarderName = wireframe.forwardUser.getDisplayName();
        if (isOut) {
          forwardingPaint.setColor(0xff739f53);
          senderPaint.setColor(0xff739f53);
        } else {
          forwardingPaint.setColor(0xff4884cf);
          senderPaint.setColor(0xff4884cf);
        }
      } else {
        isForwarded = false;
      }

      if (isGroup) {
        User user = application.getEngine().getUser(wireframe.message.getSenderId());
        this.senderName = user.getDisplayName();
      }
      if (wireframe.message.isForwarded()) {
        isForwarded = true;
        this.forwarderName = wireframe.forwardUser.getDisplayName();
      } else {
        isForwarded = false;
      }

      layoutDesiredWidth = desiredWidth;
      long start = SystemClock.uptimeMillis();

      this.spannable =
          application
              .getEmojiProcessor()
              .processEmojiCompatMutable(
                  wireframe.message.getMessage(), EmojiProcessor.CONFIGURATION_BUBBLES);

      // spannable = new SpannableString(wireframe.message.getMessage());
      Logger.d(TAG, "Emoji processed in " + (SystemClock.uptimeMillis() - start) + " ms");
      start = SystemClock.uptimeMillis();
      Linkify.addLinks(
          this.spannable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES);
      fixLinks(spannable);
      Logger.d(TAG, "Added links in " + (SystemClock.uptimeMillis() - start) + " ms");
      start = SystemClock.uptimeMillis();
      layout =
          new StaticLayout(
              spannable, bodyPaint, desiredWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
      Logger.d(TAG, "Built base layout in " + (SystemClock.uptimeMillis() - start) + " ms");

      if (layout.getLineCount() < 20) {
        int layoutTextWidth = 0;

        for (int i = 0; i < layout.getLineCount(); i++) {
          layoutTextWidth = (int) Math.max(layout.getLineWidth(i), layoutTextWidth);
        }

        if (layoutTextWidth < layout.getWidth() - px(10)) {
          layout =
              new StaticLayout(
                  spannable,
                  bodyPaint,
                  layoutTextWidth + px(2),
                  Layout.Alignment.ALIGN_NORMAL,
                  1.0f,
                  0.0f,
                  true);
        }
      }

      layoutRealWidth = layout.getWidth();

      timeWidth = (int) clockOutPaint.measureText(wireframe.date) + px((showState ? 23 : 0) + 6);

      if (layout.getLineCount() == 1) {
        boolean isLastRtl = layout.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT;
        if (!isLastRtl && desiredWidth - layoutRealWidth > timeWidth) {
          layoutRealWidth += timeWidth;
          layoutHeight = layout.getHeight() + px(3);
        } else if (isLastRtl && desiredWidth - layout.getWidth() > timeWidth) {
          layoutRealWidth = layout.getWidth() + timeWidth;
          layoutHeight = layout.getHeight() + px(3);
        } else {
          if (isLastRtl) {
            layoutRealWidth = layout.getWidth();
          }

          layoutHeight = layout.getHeight() + px(17);
        }
      } else {
        boolean isLastRtl =
            layout.getParagraphDirection(layout.getLineCount() - 1) == Layout.DIR_RIGHT_TO_LEFT;
        if (!isLastRtl
            && (desiredWidth - layout.getLineWidth(layout.getLineCount() - 1) > timeWidth)) {
          layoutRealWidth =
              (int)
                  Math.max(
                      layoutRealWidth, layout.getLineWidth(layout.getLineCount() - 1) + timeWidth);
          layoutHeight = layout.getHeight() + px(3);
        } else if (isLastRtl && (desiredWidth - layout.getWidth() > timeWidth)) {
          layoutRealWidth = (int) Math.max(layoutRealWidth, layout.getWidth() + timeWidth);
          layoutHeight = layout.getHeight() + px(3);
        } else {
          layoutHeight = layout.getHeight() + px(17);
        }
      }

      if (layoutRealWidth < timeWidth) {
        layoutRealWidth = timeWidth;
      }

      if (isForwarded) {
        layoutHeight += px(19) * 2;
        forwardOffset = (int) forwardingPaintBase.measureText("From ");
        layoutRealWidth =
            (int) Math.max(layoutRealWidth, forwardingPaintBase.measureText("Forwarded message"));
        forwarderNameMeasured =
            TextUtils.ellipsize(
                    forwarderName,
                    senderPaintBase,
                    desiredWidth - forwardOffset,
                    TextUtils.TruncateAt.END)
                .toString();
        layoutRealWidth =
            (int)
                Math.max(
                    layoutRealWidth,
                    forwardOffset + senderPaintBase.measureText(forwarderNameMeasured));
      }

      if (isGroup && !isOut && !isForwarded) {
        layoutHeight += px(19);
        senderNameMeasured =
            TextUtils.ellipsize(senderName, senderPaintBase, desiredWidth, TextUtils.TruncateAt.END)
                .toString();
        int width = (int) senderPaintBase.measureText(senderNameMeasured);
        layoutRealWidth = Math.max(layoutRealWidth, width);
      }

      Logger.d(TAG, "Build layout end");
    }
  static Bitmap[] smartNotify(Context context, Bitmap icon, String header, String body) {

    Properties props = BitmapCache.getProperties(context, "notification_sticky.xml");

    final int textTop = Integer.parseInt(props.getProperty("textTop", "24"));
    final int textLeft = Integer.parseInt(props.getProperty("textLeft", "3"));
    final int textWidth = Integer.parseInt(props.getProperty("textWidth", "85"));
    final int textHeight = Integer.parseInt(props.getProperty("textHeight", "69"));

    final int iconTop = Integer.parseInt(props.getProperty("iconTop", "0"));
    final int iconLeft = Integer.parseInt(props.getProperty("iconLeft", "0"));

    final int headerLeft = Integer.parseInt(props.getProperty("headerLeft", "20"));
    final int headerBaseline = Integer.parseInt(props.getProperty("headerBaseline", "15"));

    final int headerColor =
        props.getProperty("headerColor", "white").equalsIgnoreCase("black")
            ? Color.BLACK
            : Color.WHITE;
    final int textColor =
        props.getProperty("textColor", "black").equalsIgnoreCase("black")
            ? Color.BLACK
            : Color.WHITE;

    final int arrowUpLeft = Integer.parseInt(props.getProperty("arrowUpLeft", "91"));
    final int arrowUpTop = Integer.parseInt(props.getProperty("arrowUpTop", "23"));

    final int arrowDownLeft = Integer.parseInt(props.getProperty("arrowDownLeft", "91"));
    final int arrowDownTop = Integer.parseInt(props.getProperty("arrowDownTop", "56"));

    final int closeLeft = Integer.parseInt(props.getProperty("closeLeft", "91"));
    final int closeTop = Integer.parseInt(props.getProperty("closeTop", "89"));

    FontInfo font = FontCache.instance(context).Get();

    List<Bitmap> bitmaps = new ArrayList<Bitmap>();

    Paint paintHead = new Paint();
    paintHead.setColor(headerColor);
    paintHead.setTextSize(FontCache.instance(context).Large.size);
    paintHead.setTypeface(FontCache.instance(context).Large.face);

    Paint paint = new Paint();
    paint.setColor(textColor);
    paint.setTextSize(font.size);
    paint.setTypeface(font.face);

    Paint whitePaint = new Paint();
    whitePaint.setColor(Color.WHITE);

    TextPaint textPaint = new TextPaint(paint);
    StaticLayout staticLayout =
        new StaticLayout(
            body, textPaint, textWidth, android.text.Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false);

    int iconHeight = 16;
    int iconOffset = 0;
    if (icon != null) {
      iconHeight = Math.max(16, icon.getHeight());
      iconOffset = iconHeight - icon.getHeight(); // align icon to bottom of text
    }

    int h = staticLayout.getHeight();
    int y = 0;
    int displayHeight = textHeight + 3;

    int scroll = textHeight - font.size;
    boolean more = true;

    int pages = 0;

    while (more) {
      more = false;
      Bitmap bitmap = Bitmap.createBitmap(96, 96, Bitmap.Config.RGB_565);
      Canvas canvas = new Canvas(bitmap);

      canvas.drawColor(Color.WHITE);

      canvas.drawBitmap(Utils.getBitmap(context, "notify_background_sticky.png"), 0, 0, null);

      canvas.save();
      canvas.translate(textLeft, textTop - y); // position the text
      canvas.clipRect(0, y, textWidth, textHeight + y);
      staticLayout.draw(canvas);
      canvas.restore();

      // Draw header
      if (icon != null) canvas.drawBitmap(icon, iconLeft, iconOffset + iconTop, paint);
      canvas.drawText(header, headerLeft, headerBaseline, paintHead);

      if (y > 0)
        canvas.drawBitmap(Utils.getBitmap(context, "arrow_up.bmp"), arrowUpLeft, arrowUpTop, null);

      if ((h - y) > (displayHeight) && pages < 10) {
        more = true;
        pages++;
        canvas.drawBitmap(
            Utils.getBitmap(context, "arrow_down.bmp"), arrowDownLeft, arrowDownTop, null);
      }

      canvas.drawBitmap(Utils.getBitmap(context, "close.bmp"), closeLeft, closeTop, null);

      y += scroll;
      bitmaps.add(bitmap);
    }

    Bitmap[] bitmapArray = new Bitmap[bitmaps.size()];
    bitmaps.toArray(bitmapArray);
    return bitmapArray;
  }
  private InternalWidget.WidgetData GenWidget(String widget_id) {
    InternalWidget.WidgetData widget = new InternalWidget.WidgetData();

    widget.priority = meetingTime.equals("None") ? 0 : 1;

    String iconFile = "idle_calendar.bmp";
    if (widget_id.equals(id_0)) {
      widget.id = id_0;
      widget.description = desc_0;
      widget.width = 24;
      widget.height = 32;
    } else if (widget_id.equals(id_1)) {
      widget.id = id_1;
      widget.description = desc_1;
      widget.width = 96;
      widget.height = 32;
    } else if (widget_id.equals(id_2)) {
      widget.id = id_2;
      widget.description = desc_2;
      widget.width = 16;
      widget.height = 16;
      iconFile = "idle_calendar_10.bmp";
    } else if (widget_id.equals(id_3)) {
      widget.id = id_3;
      widget.description = desc_3;
      widget.width = 80;
      widget.height = 16;
      iconFile = "idle_calendar_10.bmp";
    } else if (widget_id.equals(id_4)) {
      widget.id = id_4;
      widget.description = desc_4;
      widget.width = 48;
      widget.height = 32;
      iconFile = null;
    } else if (widget_id.equals(id_5)) {
      widget.id = id_5;
      widget.description = desc_5;
      widget.width = 40;
      widget.height = 16;
      iconFile = null;
    }

    Bitmap icon = iconFile == null ? null : Utils.getBitmap(context, iconFile);

    widget.bitmap = Bitmap.createBitmap(widget.width, widget.height, Bitmap.Config.RGB_565);
    Canvas canvas = new Canvas(widget.bitmap);
    canvas.drawColor(Color.WHITE);

    if (widget.height == 16 && icon != null) {
      if (icon != null) canvas.drawBitmap(icon, widget.width == 16 ? 2 : 0, 0, null);
      if (meetingTime.equals("None"))
        canvas.drawText("-", widget.width == 16 ? 8 : 6, 15, paintSmallNumerals);
      else {
        // Strip out colon to make it fit;
        String time = meetingTime.replace(":", "");

        if (widget.width == 16) {
          canvas.drawText(time, 8, 15, paintSmallNumerals);
        } else {
          paintSmallNumerals.setTextAlign(Align.LEFT);
          canvas.drawText(time, 0, 15, paintSmallNumerals);
          paintSmallNumerals.setTextAlign(Align.CENTER);
        }
      }
    } else if (icon != null) {
      canvas.drawBitmap(icon, 0, 3, null);

      if ((Preferences.displayLocationInSmallCalendarWidget)
          && (!meetingTime.equals("None"))
          && (meetingLocation != null)
          && (!meetingLocation.equals("---"))
          && (widget_id.equals(id_0))
          && (meetingLocation.length() > 0)
          && (meetingLocation.length() <= 3)) {
        canvas.drawText(meetingLocation, 12, 15, paintSmall);
      } else {
        Calendar c = Calendar.getInstance();
        if ((Preferences.eventDateInCalendarWidget) && (!meetingTime.equals("None"))) {
          c.setTimeInMillis(meetingStartTimestamp);
        }
        int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
        if (dayOfMonth < 10) {
          canvas.drawText("" + dayOfMonth, 12, 16, paintNumerals);
        } else {
          canvas.drawText("" + dayOfMonth / 10, 9, 16, paintNumerals);
          canvas.drawText("" + dayOfMonth % 10, 15, 16, paintNumerals);
        }
      }
      canvas.drawText(meetingTime, 12, 30, paintSmall);
    }

    String text = "";
    if (iconFile == null) text = meetingTime;
    if ((meetingTitle != null)) {
      if (text.length() > 0) text += " : ";
      text += meetingTitle;
    }
    if ((meetingLocation != null) && (meetingLocation.length() > 0))
      text += " - " + meetingLocation;

    if (widget_id.equals(id_1) || widget_id.equals(id_4)) {

      paintSmall.setTextAlign(Align.LEFT);

      int iconSpace = iconFile == null ? 0 : 25;

      canvas.save();
      StaticLayout layout =
          new StaticLayout(
              text,
              paintSmall,
              widget.width - iconSpace,
              Layout.Alignment.ALIGN_CENTER,
              1.2f,
              0,
              false);
      int height = layout.getHeight();
      int textY = 16 - (height / 2);
      if (textY < 0) {
        textY = 0;
      }
      canvas.translate(iconSpace, textY); // position the text
      layout.draw(canvas);
      canvas.restore();

      paintSmall.setTextAlign(Align.CENTER);
    } else if (widget_id.equals(id_3) || widget_id.equals(id_5)) {
      paintSmall.setTextAlign(Align.LEFT);

      int iconSpace = iconFile == null ? 0 : 11;

      canvas.save();
      StaticLayout layout =
          new StaticLayout(
              text,
              paintSmall,
              widget.width - iconSpace,
              Layout.Alignment.ALIGN_CENTER,
              1.0f,
              0,
              false);
      int height = layout.getHeight();
      int textY = 8 - (height / 2);
      if (textY < 0) {
        textY = 0;
      }
      canvas.translate(iconSpace, textY); // position the text
      layout.draw(canvas);
      canvas.restore();

      paintSmall.setTextAlign(Align.CENTER);
    }

    return widget;
  }
  private void drawText(Canvas canvas, Bitmap bitmap, int percent, Boolean isShort) {

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    Boolean isGradient = prefs.getBoolean("gradientKey", true);

    int size = 0;
    int smallDummyHeight = 0;
    while (smallDummyHeight < ((bitmap.getHeight() / 100) * percent)) {
      TextPaint paintText = new TextPaint(Paint.ANTI_ALIAS_FLAG);
      size = size + 1;
      paintText.setTextSize(size);
      paintText.setStyle(Paint.Style.FILL_AND_STROKE);
      paintText.setShadowLayer(3f, 3f, 3f, Color.BLACK);

      Rect smallDummyRect = new Rect();
      paintText.getTextBounds(gagTitle, 0, gagTitle.length(), smallDummyRect);

      smallDummyHeight = smallDummyRect.height();
    }

    int pL = bitmap.getWidth() / 100;
    int pT = bitmap.getHeight() / 100;

    if (isShort) {

      TextPaint paintText = new TextPaint(Paint.ANTI_ALIAS_FLAG);
      paintText.setColor(Color.WHITE);
      paintText.setTextSize(size);
      paintText.setStyle(Paint.Style.FILL_AND_STROKE);
      paintText.setShadowLayer(3f, 3f, 3f, Color.BLACK);

      Rect rectText = new Rect();
      paintText.getTextBounds(gagTitle, 0, gagTitle.length(), rectText);

      if (isGradient) {
        int GRADIENT_HEIGHT = rectText.height();

        Paint paint = new Paint();
        LinearGradient shader =
            new LinearGradient(
                0, 0, 0, GRADIENT_HEIGHT, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
        paint.setShader(shader);
        canvas.drawRect(0, 0, newBitmap.getWidth(), GRADIENT_HEIGHT, paint);
      }

      canvas.drawText(gagTitle, pL, rectText.height() + (3 * pT) / 2, paintText);
    } else {

      TextPaint paintText = new TextPaint(Paint.ANTI_ALIAS_FLAG);
      paintText.setColor(Color.WHITE);
      paintText.setTextSize(size);
      paintText.setStyle(Paint.Style.FILL_AND_STROKE);
      paintText.setShadowLayer(3f, 3f, 3f, Color.BLACK);

      StaticLayout mTextLayout =
          new StaticLayout(
              gagTitle,
              paintText,
              canvas.getWidth(),
              Layout.Alignment.ALIGN_NORMAL,
              1.0f,
              0.0f,
              false);

      if (isGradient) {
        int GRADIENT_HEIGHT = mTextLayout.getHeight();

        Paint paint = new Paint();
        LinearGradient shader =
            new LinearGradient(
                0, 0, 0, GRADIENT_HEIGHT, Color.BLACK, Color.TRANSPARENT, Shader.TileMode.CLAMP);
        paint.setShader(shader);
        canvas.drawRect(0, 0, newBitmap.getWidth(), GRADIENT_HEIGHT, paint);
      }

      canvas.save();
      canvas.translate(pL, pT);
      mTextLayout.draw(canvas);
      canvas.restore();
    }
  }
  public List<Integer> getPageOffsets(CharSequence text, boolean includePageNumbers) {

    if (text == null) {
      return new ArrayList<Integer>();
    }

    List<Integer> pageOffsets = new ArrayList<Integer>();

    TextPaint textPaint = bookView.getInnerView().getPaint();
    int boundedWidth = bookView.getInnerView().getWidth();

    LOG.debug("Page width: " + boundedWidth);

    StaticLayout layout =
        layoutFactory.create(text, textPaint, boundedWidth, bookView.getLineSpacing());
    LOG.debug("Layout height: " + layout.getHeight());

    layout.draw(new Canvas());

    // Subtract the height of the top margin
    int pageHeight = bookView.getHeight() - bookView.getVerticalMargin();

    if (includePageNumbers) {
      String bottomSpace = "0\n";

      StaticLayout numLayout =
          layoutFactory.create(bottomSpace, textPaint, boundedWidth, bookView.getLineSpacing());
      numLayout.draw(new Canvas());

      // Subtract the height needed to show page numbers, or the
      // height of the margin, whichever is more
      pageHeight = pageHeight - Math.max(numLayout.getHeight(), bookView.getVerticalMargin());
    } else {
      // Just subtract the bottom margin
      pageHeight = pageHeight - bookView.getVerticalMargin();
    }

    LOG.debug("Got pageHeight " + pageHeight);

    int totalLines = layout.getLineCount();
    int topLineNextPage = -1;
    int pageStartOffset = 0;

    while (topLineNextPage < totalLines - 1) {

      LOG.debug("Processing line " + topLineNextPage + " / " + totalLines);

      int topLine = layout.getLineForOffset(pageStartOffset);
      topLineNextPage = layout.getLineForVertical(layout.getLineTop(topLine) + pageHeight);

      LOG.debug("topLine " + topLine + " / " + topLineNextPage);
      if (topLineNextPage == topLine) { // If lines are bigger than can fit on a page
        topLineNextPage = topLine + 1;
      }

      int pageEnd = layout.getLineEnd(topLineNextPage - 1);

      LOG.debug("pageStartOffset=" + pageStartOffset + ", pageEnd=" + pageEnd);

      if (pageEnd > pageStartOffset) {
        if (text.subSequence(pageStartOffset, pageEnd).toString().trim().length() > 0) {
          pageOffsets.add(pageStartOffset);
        }
        pageStartOffset = layout.getLineStart(topLineNextPage);
      }
    }

    return pageOffsets;
  }